跟进:缺少 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】:

由于ch1ch2 这两个字段在您的情况下始终是必需的,您需要做的就是修改您的模型,以便

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 被保存为空字符串并且不会引发错误的主要内容,如果未能解决你的问题,请参考以下文章

modelForm所遇问题

即使缺少所需的值,Django 验证也会调用 clean()

Django TokenAuthentication 缺少“授权”http 标头

Django的ModelForm

Django之ModelForm组件

django的modelform怎么设置required=False