如何在Django中使用模型清理方法并遍历字段

时间:2019-10-01 13:47:24

标签: django validation model modelform

我问了一个问题,我已经读了一点,现在我可以更好地表达我的需求了: How to do model level custom field validation in django?

我有这个模型:

class StudentIelts(Model):

    SCORE_CHOICES = [(i/2, i/2) for i in range(0, 19)]

    student = OneToOneField(Student, on_delete=CASCADE)
    has_ielts = BooleanField(default=False,)
    ielts_listening = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_reading = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_writing = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_speaking = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )

并具有以下模型形式:

class StudentIeltsForm(ModelForm):

    class Meta:
        model = StudentIelts
        exclude = ('student')

    def clean(self):
        cleaned_data = super().clean()
        has_ielts = cleaned_data.get("has_ielts")

        if has_ielts:
            msg = "Please enter your score."
            for field in self.fields:
                if not self.cleaned_data.get(str(field)):
                    self.add_error(str(field), msg)

        else:
            for field in self.fields:
                self.cleaned_data[str(field)] = None
                self.cleaned_data['has_ielts'] = False

        return cleaned_data

我在这里所做的是检查has_ielts是否为True,然后应填写所有其他字段。如果has_ieltsTrue,甚至没有填写一个字段,我都会收到错误消息。如果has_ieltsFalse,则应保存一个带有has_ielts=False和所有其他字段Null的对象。我现在想在模型级别执行此操作:

class StudentIelts(Model):

    SCORE_CHOICES = [(i/2, i/2) for i in range(0, 19)]

    student = OneToOneField(Student, on_delete=CASCADE)
    has_ielts = BooleanField(default=False,)
    ielts_listening = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_reading = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_writing = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    ielts_speaking = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )

    def clean(self):
    # I do not know what to write in here

并具有以下模型形式:

class StudentIeltsForm(ModelForm):

    class Meta:
        model = StudentIelts
        exclude = ('student')

在我的模型的clean方法中,我想要具有此逻辑的东西(这是psedue代码):

def clean(self):
    msg = "Please enter your score."

    if self.has_ielts:
        my_dic = {}
        for f in model_fields:
             if f is None:
                  my_dic.update{str(field_name): msg}
        raise ValidationError(my_dic)

我该怎么做?
如何在模型级别上获得与模型形式相同的结果?

1 个答案:

答案 0 :(得分:1)

您需要显式声明应为非空的字段,否则您将循环浏览与清理方法无关的字段,例如idstudent。有人可能想在以后添加一个非必填字段,并想知道为什么会引起验证错误。

class StudentIelts(Model):

    # fields

    non_empty_fields = ['ielts_reading', ...]

    def clean(self):
        errors = {}
        if self.has_ielts:
            for field_name in self.non_empty_fields:
                if not getattr(self, field_name):
                    errors[field_name] = msg
        if errors:
            raise ValidationError(errors)