跟进:缺少 django Modelform 中所需的 Charfield 被保存为空字符串并且不会引发错误
Posted
技术标签:
【中文标题】跟进:缺少 django Modelform 中所需的 Charfield 被保存为空字符串并且不会引发错误【英文标题】:Followup : missing required Charfield in django Modelform is saved as empty string and do not raise an error 【发布时间】:2017-02-05 22:24:16 【问题描述】:如果我尝试在 Django 1.10 中保存不完整的模型实例,我希望 Django 会引发错误。好像不是这样的。
models.py:
from django.db import models
class Essai(models.Model):
ch1 = models.CharField(max_length=100, blank=False)
ch2 = models.CharField(max_length=100, blank=False)
所以我有两个字段不允许为空(默认行为,NOT NULL
限制由 Django 在创建 mysql 表时应用)。如果在存储之前未设置其中一个字段,我希望 Django 引发错误。
但是,当我创建一个不完整的实例时,数据存储得很好:
>>> from test.models import Essai
>>> bouh = Essai()
>>> bouh.ch1 = "some content for ch1"
>>> bouh.save()
>>> bouh.id
9
>>> bouh.ch1
'some content for ch1'
>>> bouh.ch2
''
>>>
我本以为 Django 会引发错误。但是,如果我将ch2
强制为None
,则会引发错误:
>>> bouh = Essai()
>>> bouh.ch1 = "some content for ch1"
>>> bouh.ch2 = None
>>> bouh.save()
Traceback (most recent call last):
(...)
return Database.Cursor.execute(self, query, params)
django.db.utils.IntegrityError: NOT NULL constraint failed: test_essai.ch2
>>> bouh.id
>>> bouh.ch1
'some content for ch1'
>>> bouh.ch2
>>>
说明:在这种简单情况下,Django 不会将错误作为默认行为,因为在 SQL 中,空字符串 ""
不等于 NULL,如 Django model blank=False does not work? 中所述
现在,如果我们查看 ModelForm 的行为,django doc 中似乎存在不一致:
根据: https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#selecting-the-fields-to-use
Django 将阻止任何尝试保存不完整的模型,因此如果模型不允许缺失的字段为空,并且不为缺失的字段提供默认值,则任何尝试 save() 缺失的 ModelForm字段将失败。为避免此失败,您必须使用缺失但必填字段的初始值来实例化您的模型:(...)
如果没有默认值,则不应使用缺少的字段保存模型表单。
所以有了这个 ModelForm:
class EssaiModelForm(forms.ModelForm):
class Meta:
model = Essai
fields = ['ch1']
生成一个只有一个字段ch1
的表单。
ch1
留空,验证将在EssaiModelFormInstance.is_valid()
处按预期失败。
如果ch1
包含一个值,即使ch2
仍然缺失,验证也会成功。然后 EssaiModelFormInstance.save() 成功,这与 django 文档中声称的相反。 ch2
是空字符串,因此符合 SQL 要求 (NOT NULL
)。
因此,似乎 Charfield 有一个默认默认值空字符串 ""
,在表单验证中 不接受,但在 save() 验证中 接受 .这可能需要在文档中进行说明。
【问题讨论】:
原帖:***.com/questions/39714214/… 【参考方案1】:由于ch1
和ch2
这两个字段在您的情况下始终是必需的,您需要做的就是修改您的模型,以便
from django.db import models
class Essai(models.Model):
ch1 = models.CharField(max_length=100)
ch2 = models.CharField(max_length=100)
并将表单中的字段包含为
class EssaiModelForm(forms.ModelForm):
class Meta:
model = Essai
fields = ['ch1', 'ch2']
Django 将在is_valid()
上自动引发此字段的验证错误
或者如果您想禁止在这些字段中输入空字符串,blank=False
将不起作用
参考这个Django - how to set blank = False, required = False
【讨论】:
【参考方案2】:模型及其形式略有不同。 Model.save() 不执行验证。因此,如果它失败,那么它可能会引发数据库级别的 IntegrityError。为了降低数据库层失败的风险,需要调用 Model.full_clean() 这也是由 ModelForm 完成的,如django's validating objects 中所述。
在我看来,我希望 django 将 ModelForms 用于验证和保存客户端输入的数据。以编程方式实例化的模型在保存到数据库之前应遵循相同的控制。
【讨论】:
以上是关于跟进:缺少 django Modelform 中所需的 Charfield 被保存为空字符串并且不会引发错误的主要内容,如果未能解决你的问题,请参考以下文章
即使缺少所需的值,Django 验证也会调用 clean()