【问题标题】:Django model.full_clean() allows invalid value for IntegerFieldDjango model.full_clean() 允许 IntegerField 的值无效
【发布时间】:2014-08-31 05:03:51
【问题描述】:

我有一些带有继承的模型,看起来像这样:

Class A(models.Model):
    some_text = models.CharField(max_length=100)
    #other fields, not important

Class B(A):
    some_int = models.IntegerField(blank=True, null=True, validators=[MinValueValidator(1), MaxValueValidator(1000)])

然后我启动 Django shell 并执行以下操作:

>>> obj = B()
>>> obj.some_text = 'foo'
>>> obj.some_int = 'bar'
>>> obj.full_clean()

我很自然地得到:

>>> ValidationError: {'some_int': [u"'bar' value must be an integer."]}

很好。那么:

>>> obj.some_int = '   ' #whitespace
>>> obj.full_clean()

我得到:

>>> ValidationError: {'some_int': [u"'   ' value must be an integer."]}

完美。但后来我尝试了一个空字符串:

>>> obj.some_int = '' #empty string
>>> obj.full_clean()

没有引发 ValidationError,但如果我尝试保存对象:

>>> obj.save()

我明白了:

>>> ValueError: invalid literal for int() with base 10: ''

这里发生了什么?这是正确的行为吗? Django 如何检查该值是否为有效整数?

我真的不想自定义我的模型的 clean() 函数来检查这个,但它开始看起来我别无选择。

编辑:Django 1.6.5、Python 2.7.6、Windows 7 64 位。

【问题讨论】:

    标签: django django-models django-validation


    【解决方案1】:

    clean_fields 方法中注释了这种行为的原因:

        def clean_fields(self, exclude=None):
        """
        Cleans all fields and raises a ValidationError containing message_dict
        of all validation errors if any occur.
        """
        if exclude is None:
            exclude = []
    
        errors = {}
        for f in self._meta.fields:
            if f.name in exclude:
                continue
            # Skip validation for empty fields with blank=True. The developer
            # is responsible for making sure they have a valid value.
            raw_value = getattr(self, f.attname)
            if f.blank and raw_value in f.empty_values:
                continue
            try:
                setattr(self, f.attname, f.clean(raw_value, self))
            except ValidationError as e:
                errors[f.name] = e.error_list
    
        if errors:
            raise ValidationError(errors)
    

    【讨论】:

    • Welp...你是对的。我想这有一个很好的理由,我目前无法完全理解。尽管如此,看到它明确写到我负责用blank=True 验证一个空字段,这让解决方案感觉不那么脏/乱。谢谢。
    【解决方案2】:

    你得到这个行为是因为你有blank=True。我同意你的观点,你看到的行为很奇怪——这是 Django model 验证与 form 验证紧密相关的一个症状,即使原则上它们可以分开。

    假设您确实想要blank=Truenull=True,我不会担心这个。表单会做正确的事情(将表单中的空字符串转换为数据库中的NULL 值),模型和数据库实际上不会让您保存无效值。唯一的问题是,如果您有不涉及 Django 表单的数据输入,则会在save() 时间而不是full_clean() 时间引发错误。

    当然,如果您不想为该字段设置NULL 值,只需设置blank=False, null=Falsefull_clean() 就会像您期望的那样抱怨空字符串。

    【讨论】:

    • 不幸的是,该字段必须保留blank=False, null=False...而且我确实有不涉及 Django 表单的数据输入。看来我得自己检查一下了。感谢您的洞察力。
    【解决方案3】:

    那是因为您允许您的字段为空白(也为空)。 所以没关系,它是有效的。

    如果您不希望这样,只需删除 blank=True 选项或将其更改为 blank=False

    【讨论】:

    • 如果“没问题且有效”,那么为什么在我尝试保存对象时会引发异常?如果我将值设置为无,它工作正常。当我调用 full_clean() 时它不会引发验证错误,而当我调用 save() 时它不会引发值错误。这只发生在空字符串中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-31
    • 2016-03-10
    • 2019-12-09
    • 1970-01-01
    • 2016-01-18
    • 2020-08-03
    • 2020-06-05
    相关资源
    最近更新 更多