这是验证Django模型字段的方法吗?

Ray*_*Ray 23 python django django-models

据我所知,当一个人创建一个Django应用程序时,在将表单插入到模型实例中然后将其写入数据库之前,表单会对数据进行验证.但是如果我想在数据模型层创建一个额外的保护层,那么我在目前的"最佳实践"下面做了什么?我正在努力确保评论者的名字不能被省略,也不能留空.我应该在'clean'方法中进行任何自定义验证,就像我在这里做的那样然后'保存'调用'full_clean'调用'clean'?如果不是,那么首选方法是什么?谢谢.

class Reviewer(models.Model):
    name = models.CharField(max_length=128, default=None)

    def clean(self, *args, **kwargs):
        if self.name == '':
            raise ValidationError('Reviewer name cannot be blank')
        super(Reviewer, self).clean(*args, **kwargs)

    def full_clean(self, *args, **kwargs):
        return self.clean(*args, **kwargs)

    def save(self, *args, **kwargs):
        self.full_clean()
        super(Reviewer, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

Ala*_*air 27

首先,你不应该full_clean像你所做的那样覆盖.来自full_cleandjango文档:

Model.full_clean(exclude=None)
此方法按顺序调用Model.clean_fields(),, Model.clean()Model.validate_unique(),并引发ValidationError具有message_dict包含所有三个阶段的错误的属性.

所以该full_clean方法已经调用clean,但是通过覆盖它,你已经阻止它调用其他两个方法.

其次,调用full_cleansave方法是一种权衡.请注意,full_clean在验证模型表单时已经调用过,例如在Django管理员中.所以,如果你full_cleansave方法,那么该方法将运行两次.

通常不期望save方法引发验证错误,有人可能会调用save而不会捕获结果错误.但是,我喜欢你调用full_clean而不是在save方法中进行检查 - 这种方法允许模型表单首先捕获问题.

最后,您的clean方法可行,但您实际上可以在模型字段本身处理您的示例案例.定义你CharField

name = models.CharField(max_length=128)
Run Code Online (Sandbox Code Playgroud)

blank选项默认为False.如果该字段为空白,ValidationError则在运行时将引发a full_clean.把default=NoneCharField没有做任何伤害,但它是一个有点混乱,当你实际上并没有允许None作为值.


Ray*_*Ray 7

在考虑了 Alasdair 的回答并进行了额外的阅读之后,我现在的感觉是 Django 的模型并没有像我试图做的那样设计为仅在模型的基础上进行验证。可以进行此类验证,但需要付出一定的代价,并且需要以非预期的方式使用验证方法。

相反,我现在认为,除了可以直接输入模型字段声明(例如“unique=True”)的约束之外,任何约束都应该作为 Form 或 ModelForm 验证的一部分执行。如果想防止通过任何其他方式(例如在 Python 解释器中工作时通过 ORM)将无效数据输入到项目的数据库中,那么验证应该在数据库本身内进行。因此,验证可以在三个层次上实现: 1) 首先,通过数据库中的 DDL 实现所有约束和触发器;2) 实现对您的模型字段可用的任何约束(例如“unique=True”);和 3) 实现所有其他约束和验证,这些约束和验证反映了您的 Forms 和 ModelForms 中的数据库级约束和触发器。通过这种方法,任何表单验证错误都可以重新显示给用户。如果程序员通过 ORM 直接与数据库交互,他/她将直接看到数据库异常。

有人想吗?

  • 我在数据库中发现了额外的逻辑 icky。你在哪里添加这个逻辑?你在哪里测试?您如何在安装之间保持同步?测试?版本控制?如果您打算这样做,那么您应该找到一种方法将它集成到您​​的模型声明中,以便它与其他所有内容一起在 Python 代码中可见。自定义字段类型?模型混合? (14认同)

Kev*_*ker 6

在我的模型上捕获预保存信号确保 clean 将被自动调用。

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')
Run Code Online (Sandbox Code Playgroud)