在 Django CharFields 中自动截断 max_length 字段

Posted

技术标签:

【中文标题】在 Django CharFields 中自动截断 max_length 字段【英文标题】:Auto-truncating fields at max_length in Django CharFields 【发布时间】:2011-03-28 10:53:27 【问题描述】:

我有一个设置了max_length 的字段。当我保存模型实例并且该字段的值大于max_length 时,Django 在数据库级别强制执行max_length。 (参见模型上的 Django 文档:http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.CharField.max_length)

但是,由于我使用的是 Postgres,我收到了一个 DatabaseError 异常,如下所示:

DatabaseError: value too long for type character varying(1000)

我宁愿自动截断值(所以我没有例外)。现在,我可以手动执行此操作,但我真正想要的是让我的所有模型自动截断该值。 (不一定聪明。只要在第 999 个字符处将其切断即可。)

我是否应该编写一个从 models.Model 导入的自定义类并覆盖 save() 方法,循环遍历每个 _meta.field,检查 max_length,然后截断?这似乎不优雅,必须有更好的方法。

【问题讨论】:

【参考方案1】:

你为什么不使用ModelForm。 ModelForm 强制执行验证,将其默认 max_length 设置为模型字段的 max_length 属性,并在调用 form.is_valid() 时引发适当的验证错误。这样您就不必保存表单,直到表单得到验证。

或者,如果您想静默通过验证并截断最适合您的,请编写一个简单的 django 表单,并编写一个干净的方法,将输入字符串截断为 max_length 并返回剥离的数据。验证表单后从form.cleaned_data 获取数据并保存对象。

考虑到这一事实,表单旨在在进入数据库之前验证数据。

【讨论】:

【参考方案2】:

为什么不使用 TextField?来自手册:

对于大量文本,请使用 文本字段。

【讨论】:

是的,看看你写的东西,如果你想在第 999 个字符处截断它,这表明 TextField 可能是更好的选择。 很好的答案,但可能是另一个问题。【参考方案3】:

您可以创建一个自动截断字段的自定义字段(我认为这段代码应该可以工作,但请仔细检查):

class TruncatingCharField(models.CharField):
    def get_prep_value(self, value):
        value = super(TruncatingCharField,self).get_prep_value(value)
        if value:
            return value[:self.max_length]
        return value

然后,您无需在 models.py 文件中使用 models.CharField,而是使用 TruncatingCharField。

get_prep_value 为要插入数据库的字段准备值,因此它是截断的理想位置。

【讨论】:

工作就像一个魅力! 放在哪里? 已经使用这个glady 2 年多了,只有一件事要强调:在使用.create(或导致创建的变体,例如get_or_create)之后,内存中的实例将不会t 截断该字段。很好记住! refresh_from_db 显示它已正确截断,但在创建对象后必须立即刷新它不是很好.. 无论如何我都找不到从 Field 类本身来控制它,所以我最终将 Field.get_prep_value() 添加到具有 TruncateCharField 的模型的 save() 方法中...... 在对值进行切片之前,我们应该剥离()它。【参考方案4】:

这看起来很不雅,一定有更好的办法。

首先发生截断行为的唯一原因是 mysql 未能遵守 SQL 标准。尝试将字符串插入到宽度不足以容纳它的 VARCHAR 字段中时,抛出异常是正确的响应。 MySQL 会截断并插入。

如果您想悄悄地破坏您的数据,那么您将不得不以某种方式手动完成——PostgreSQL 永远不会为您完成。

【讨论】:

问题是关于 Django,而不是关于 PostgreSQL。我喜欢 PostgreSQL 遵守标准并引发错误,但我(也像 OP 一样)喜欢让 Django 知道可以截断(在尝试插入之前)。 好的,默认情况下这样做是错误的。但是可以选择自动执行此操作。

以上是关于在 Django CharFields 中自动截断 max_length 字段的主要内容,如果未能解决你的问题,请参考以下文章

截断 Django CMS 占位符

在 django 中截断 html 文本

在Django中截断文本但向后方向

有没有办法在Django的视图中截断单词?

如何在 Django 模板引擎上截断/切片字符串?

将 JSONField 解压缩到多个 django 表单字段中