3

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

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 位。

4

3 回答 3

5

这种行为的原因在 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)
于 2014-08-31T09:18:18.313 回答
2

你得到这种行为是因为你有blank=True. 我同意你的观点,你看到的行为很奇怪——这表明在 Django 中模型验证与表单验证非常紧密地联系在一起,即使原则上它们可以分开。

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

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

于 2014-08-31T08:26:18.730 回答
0

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

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

于 2014-08-31T08:16:43.507 回答