小编典典

Django模型字段验证

python

模型字段 的验证在django中应该去哪里?

我可以至少命名两个可能的选择:在模型的重载.save()方法中或在模型.field_子类的.to_python()方法中(显然,要工作,您必须编写自定义字段)。

可能的用例:

  • 当绝对需要确保不会将空字符串写入数据库时​​(blank = False关键字参数在这里不起作用,仅用于表单验证)
  • 当需要确保“选择”关键字参数在数据库级别且不仅在管理界面中受到尊重时(类似于枚举数据类型)

模型中还有一个类级别的属性。字段empty_strings_allowed基类定义和派生类很高兴地覆盖它,但是它似乎对数据库级别没有任何影响,这意味着我仍然可以使用空字符串字段构建模型并将其保存到数据库。我要避免的(是,这是必要的)。

可能的实现方式是

在现场一级:

class CustomField(models.CharField):
    __metaclass__ = models.SubfieldBase
    def to_python(self, value):
        if not value:
            raise IntegrityError(_('Empty string not allowed'))
        return models.CharField.to_python(self, value)

在模型级别:

class MyModel(models.Model)
    FIELD1_CHOICES = ['foo', 'bar', 'baz']
    field1 = models.CharField(max_length=255, 
               choices=[(item,item) for item in FIELD1_CHOICES])

    def save(self, force_insert=False, force_update=False):
        if self.field1 not in MyModel.FIELD1_CHOICES:
            raise IntegrityError(_('Invalid value of field1'))
        # this can, of course, be made more generic
        models.Model.save(self, force_insert, force_update)

也许,我缺少了一些东西,而且可以做得更容易(更清洁)?


阅读 200

收藏
2021-01-20

共1个答案

小编典典

自版本1.2起,Django已有模型验证系统。

sebpiq在评论中说:“好吧,现在有地方放置模型验证了……除了仅在使用ModelForm时才运行模型验证!因此问题仍然存在,何时有必要确保在数据库级尊重验证,该怎么办?在哪里调用full_clean?”

无法通过Python级别的验证来确保在db级别上遵守验证。最接近的可能是调用full_clean重写的save方法。默认情况下不会执行此操作,因为这意味着每个调用该save方法的人现在最好都准备好捕获和处理ValidationError

但是即使您执行此操作,仍然有人可以使用来批量更新模型实例queryset.update(),这将绕过此验证。Django无法实现一种合理有效的方法queryset.update(),该方法仍然可以对每个更新的对象执行Python级别的验证。

真正保证数据库级完整性的唯一方法是通过数据库级​​约束。您通过ORM进行的任何验证都要求应用程序代码的编写者知道何时执行验证(并处理验证失败)。

这就是为什么默认情况下仅在in中强制执行模型验证的ModelForm原因,因为在ModelForm中已经存在一种明显的方法来处理ValidationError

2021-01-20