代码之家  ›  专栏  ›  技术社区  ›  shylent

Django模型字段验证

  •  56
  • shylent  · 技术社区  · 16 年前

    在哪里验证 去Django吗?

    我至少可以说出两个可能的选择:在模型的overloaded.save()方法中,或者在models.field子类的.to-python()方法中(显然,要使其有效,必须编写自定义字段)。

    可能的用例:

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

    还有一个类级属性 empty_strings_allowed 在models.field中,基类定义和派生类很乐意重写它,但是它似乎不会对数据库级别产生任何影响,这意味着我仍然可以用空字符串字段构建模型并将其保存到数据库中。我想避免(是的,这是必要的)。

    可能的实现是

    在现场层面:

    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)
    

    也许,我遗漏了一些东西,这样做更容易(更干净)?

    4 回复  |  直到 10 年前
        1
  •  60
  •   Carl Meyer    14 年前

    Django有一个 model validation 自1.2版起,系统已就位。

    在评论中,sebbiq说“好吧,现在有一个地方可以进行模型验证……但它只在使用模型窗体时运行!所以问题仍然存在,当需要确保在数据库级别遵守验证时,您应该怎么做?在哪里打满“干净”?

    不能通过Python级别的验证来确保在DB级别上遵守验证。最接近的可能是打电话 full_clean 在重写的 save 方法。这在默认情况下不是这样做的,因为这意味着调用save方法的每个人现在最好准备好捕获和处理 ValidationError .

    但即使这样做,仍有人可以使用 queryset.update() ,这将绕过此验证。Django不可能实现一个相当高效的 查询集.update()) 它仍然可以对每个更新的对象执行Python级别的验证。

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

    这就是为什么模型验证在默认情况下只在 ModelForm -因为在模型窗体中,已经有一种明显的方法来处理 验证错误 .

        2
  •  6
  •   Darius    15 年前

    我想你想要这个->

    from django.db.models.signals import pre_save
    
    def validate_model(sender, **kwargs):
        if 'raw' in kwargs and not kwargs['raw']:
            kwargs['instance'].full_clean()
    
    pre_save.connect(validate_model, dispatch_uid='validate_models')
    

    (抄袭) http://djangosnippets.org/snippets/2319/ )

        3
  •  3
  •   rrauenza    10 年前

    这个问题的根本问题是验证应该发生在模型上。这在Django(开发人员邮件列表上的搜索表单模型感知验证)中已经讨论了相当长的时间。它会导致重复,或者在命中数据库之前逃避验证。

    虽然没有撞到后备箱,马尔科姆的 "poor man's model validation solution" 可能是避免重复的最干净的解决方案。

        4
  •  1
  •   Oduvan    16 年前

    如果我“清楚地”理解您的意思,您必须重写函数get-db-prep-save而不是to-python