我对模型的clean()
方法和基本字段验证有问题。这是我的模型和clean()
方法。
class Trial(models.Model):
trial_start = DurationField()
movement_start = DurationField()
trial_stop = DurationField()
def clean(self):
from django.core.exceptions import ValidationError
if not (self.movement_start >= self.trial_start):
raise ValidationError('movement start must be >= trial start')
if not (self.trial_stop >= self.movement_start):
raise ValidationError('trial stop must be >= movement start')
if not (self.trial_stop > self.trial_start):
raise ValidationError('trial stop must be > trial start')
我的clean()
方法检查某些值是否在正确的范围内。如果用户忘记填写字段,例如movement_start
,那么我会得到一个错误:
can't compare datetime.timedelta to NoneType
我很惊讶我得到了这个错误,因为最初的clean()
函数应该会捕获丢失的条目(毕竟movement_start
是一个必填字段)。那么,我如何进行缺失值的基本检查,以及自定义检查值是否在特定范围内呢?这可以用模型的clean()
方法完成吗?还是我需要使用Forms
?
EDIT1使其更清楚:trial_start
、movement_start
和trial_stop
都是必填字段。我需要编写一个clean()
方法,它首先检查所有三个字段是否都已填写完毕,然后检查值是否在特定范围内。
例如,以下代码不起作用,因为trial_start
可能为空。我想避免检查每个字段的存在-django应该为我做这件事。
class TrialForm(ModelForm):
class Meta:
model = Trial
def clean_movement_start(self):
movement_start = self.cleaned_data["movement_start"]
trial_start = self.cleaned_data["trial_start"]
if not (movement_start >= trial_start):
raise forms.ValidationError('movement start must be >= trial start')
return self.cleaned_data["movement_start"]
EDIT2我之所以要将此检查添加到模型的clean()
方法中,是因为在python shell上创建的对象将自动检查是否有正确的值。表单对视图来说很好,但我也需要对shell进行值检查。
我想这就是前进的道路:
class TrialForm(ModelForm):
class Meta:
model = Trial
def clean(self):
data = self.cleaned_data
if not ('movement_start' in data.keys() and 'trial_start' in data.keys() and 'trial_stop' in data.keys()):
raise forms.ValidationError("Please fill out missing fields.")
trial_start = data['trial_start']
movement_start = data['movement_start']
trial_stop = data['trial_stop']
if not (movement_start >= trial_start):
raise forms.ValidationError('movement start must be >= trial start')
if not (trial_stop >= movement_start):
raise forms.ValidationError('trial stop must be >= movement start')
if not (trial_stop > trial_start):
raise forms.ValidationError('trial stop must be > trial start')
return data
EDIT这种方法的缺点是,只有当我通过窗体创建对象时,值检查才会起作用。在python shell上创建的对象不会被检查。
我知道这已经很晚了,但要回答为什么最终会发生这种情况:没有"原始清洁"。clean方法是自定义验证的挂钩,因此您是提供其代码的人。不确定OP是如何使用clean hook的,但是:在定义它之后,您应该在模型上调用full_clean()
,这样Django就可以完整地运行模型验证。请参阅文档中调用不同验证方法的顺序等的详细信息https://docs.djangoproject.com/en/1.11/ref/models/instances/#validating-对象(可能需要注意的是:full_clean()
不是由模型的save()
自动调用的,这也是为什么当你使用shell并直接保存时,你会跳过验证的部分原因)
(请注意,ModelForms也有各种验证步骤,并将调用模型的full_clean:https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#validation-a-modelform)
我遇到了类似的问题,但遇到了ForeignKey
。在您的情况下,我只检查字段是否为空,并简化您的布尔表达式:
class Trial(models.Model):
trial_start = DurationField()
movement_start = DurationField()
trial_stop = DurationField()
def clean(self):
from django.core.exceptions import ValidationError
if self.trial_start:
if self.movement_start and self.movement_start < self.trial_start:
raise ValidationError('movement start must be >= trial start')
if self.trial_stop:
if self.trial_stop <= self.trial_start:
raise ValidationError('trial stop must be > trial start')
if self.movement_start:
if self.trial_stop < self.movement_start:
raise ValidationError('trial stop must be >= movement start')
您可以在模型中添加以下代码:
def save(self, *args, **kwargs):
self.full_clean()
return super().save(*args, **kwargs)
有了这个,无论您在哪里创建对象(窗体、视图、shell、测试),都将调用验证。