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_clean的django文档:
Model.full_clean(exclude=None)
此方法按顺序调用Model.clean_fields(),,Model.clean()和Model.validate_unique(),并引发ValidationError具有message_dict包含所有三个阶段的错误的属性.
所以该full_clean方法已经调用clean,但是通过覆盖它,你已经阻止它调用其他两个方法.
其次,调用full_clean该save方法是一种权衡.请注意,full_clean在验证模型表单时已经调用过,例如在Django管理员中.所以,如果你full_clean的save方法,那么该方法将运行两次.
通常不期望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=None你CharField没有做任何伤害,但它是一个有点混乱,当你实际上并没有允许None作为值.
在考虑了 Alasdair 的回答并进行了额外的阅读之后,我现在的感觉是 Django 的模型并没有像我试图做的那样设计为仅在模型的基础上进行验证。可以进行此类验证,但需要付出一定的代价,并且需要以非预期的方式使用验证方法。
相反,我现在认为,除了可以直接输入模型字段声明(例如“unique=True”)的约束之外,任何约束都应该作为 Form 或 ModelForm 验证的一部分执行。如果想防止通过任何其他方式(例如在 Python 解释器中工作时通过 ORM)将无效数据输入到项目的数据库中,那么验证应该在数据库本身内进行。因此,验证可以在三个层次上实现: 1) 首先,通过数据库中的 DDL 实现所有约束和触发器;2) 实现对您的模型字段可用的任何约束(例如“unique=True”);和 3) 实现所有其他约束和验证,这些约束和验证反映了您的 Forms 和 ModelForms 中的数据库级约束和触发器。通过这种方法,任何表单验证错误都可以重新显示给用户。如果程序员通过 ORM 直接与数据库交互,他/她将直接看到数据库异常。
有人想吗?
在我的模型上捕获预保存信号确保 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)