模型和字段验证中的clean()方法

时间:2012-09-05 09:53:54

标签: django

我对模型的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_startmovement_starttrial_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进行值检查。

3 个答案:

答案 0 :(得分:6)

我想这是要走的路:

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

编辑这种方法的缺点是,只有通过表单创建对象时,值检查才有效。不会检查在python shell上创建的对象。

答案 1 :(得分:2)

我知道这已经很晚了,但要回答为什么最终会发生在这里的人可能会发生这种情况:没有"原来干净"。 clean方法是自定义验证的钩子,因此您就是提供其代码的人。不确定OP是如何使用干净钩子的,但是:在定义它之后,你应该在模型上调用full_clean(),以便Django完整地运行模型验证。请参阅文档中有关其调用不同验证方法的顺序的详细信息,例如https://docs.djangoproject.com/en/1.11/ref/models/instances/#validating-objects(可能需要注意的重要提示:full_clean()不会被模型save()自动调用{ {1}}这就是为什么当你使用shell并直接保存时你会跳过验证的原因之一

(注意ModelForms也有各种验证步骤,并会调用模型&fulls.clean:https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#validation-on-a-modelform

答案 2 :(得分:0)

我正在努力解决类似的问题但是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') 。在你的情况下,我只会检查字段是否为空,我会简化你的布尔表达式:

myproject
   utils
      tool1.py
   datasets
      create_bla_dataset.py
   research
      mynote.ipynb