Vie*_*iet 29 django django-models django-forms
在进行子类化时db.models.Model,有时需要添加额外的检查/约束.
例如,我有一个Event带start_date和的模型end_date.
我想在字段或模型中添加验证,以便end_date > start_date.
有多少种方法可以做到这一点?
至少我知道这可以models.Model在ModelForm验证内部完成.
但是如何依附于田野和models.Model?
ste*_*anw 51
我不会在save方法中加入这样的约束,为时已晚.在那里引发异常对于以错误方式输入数据的用户没有帮助,因为它最终会以500结尾,并且用户将无法获得返回错误的表单等.
您应该在Forms/ModelForms clean方法中检查这一点并引发ValidationError,因此form.is_valid()返回false并且您可以将表单中的错误发送回用户进行更正.
另请注意,自1.2版以来,Django已经进行了模型验证.
它看起来像这样:
class Foo(models.Model):
# ... model stuff...
def clean(self):
if self.start_date > self.end_date:
raise ValidationError('Start date is after end date')
Run Code Online (Sandbox Code Playgroud)
Rei*_*ica 20
从 Django 2.2 开始,constraints支持数据库级别:
from django.db import models
from django.db.models import CheckConstraint, Q, F
class Event(models.Model):
start_date = models.DatetimeField()
end_date = models.DatetimeField()
class Meta:
constraints = [
CheckConstraint(
check = Q(end_date__gt=F('start_date')),
name = 'check_start_date',
),
]
Run Code Online (Sandbox Code Playgroud)
Ser*_*nko 11
在您的模型的保存方法中执行此操作:
def save(self, *args, **kwargs):
if(self.end_date > self.start_date):
super(Foo, self).save(*args, **kwargs)
else:
raise Exception, "end_date should be greater than start_date"
Run Code Online (Sandbox Code Playgroud)
Mar*_*ark 10
正如@stefanw所说,检查表单的干净方法是更好的用户体验.
如果你非常确定没有,也永远不会是另一种改变价值的方法,这就足够了.但由于您很少能够确定,如果数据库一致性很重要,您可以添加另一个检查(除了表单),其中一个:
要"完全"确保数据库是一致的,您可以添加数据库级别约束.例如,您可以使用RunSQL和SQL 创建迁移,类似于(未测试):
migrations.RunSQL('ALTER TABLE app_event ADD CONSTRAINT chronology CHECK (start_date > end_date);')
Run Code Online (Sandbox Code Playgroud)
(未经测试).这可能与数据库有关,当然这是一个缺点.
在您的示例中,它可能不值得(不正确的开始/结束时间看起来有点奇怪,但只影响一个不一致的事件),并且您不希望手动更改架构.但它在一致性至关重要的情况下很有用.
编辑:您也可以只保存开始时间和持续时间,而不是开始和结束时间.