21

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

4

4 回答 4

11

我想这就是要走的路:

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 上创建的对象。

于 2012-09-05T10:28:38.617 回答
4

我知道这已经晚了,但要回答为什么这可能会发生在最终来到这里的人身上:没有“原始清洁”。clean 方法是一个自定义验证的钩子,所以你是提供它的代码的人。不确定 OP 是如何使用 clean 钩子的,但是:在定义它之后,你应该调用full_clean()你的模型,以便 Django 完整地运行模型验证。请参阅文档中的详细信息,了解它调用不同验证方法的顺序,例如https://docs.djangoproject.com/en/1.11/ref/models/instances/#validating-objects(可能需要注意:full_clean()是'不会被模型自动调用,save()这就是为什么当您使用外壳并立即保存时您将跳过验证的部分原因)

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

于 2017-12-07T20:24:00.637 回答
1

我正在努力解决类似的问题,但使用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')
于 2017-08-16T22:07:20.657 回答
1

您可以在模型中添加以下代码:

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

无论您在何处创建对象(表单、视图、外壳、测试),都将调用验证。

于 2021-09-15T16:09:31.080 回答