在 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 字段的主要内容,如果未能解决你的问题,请参考以下文章