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

How to use model clean method in django and iterate over fields

我问了一个问题,我读了一点书,现在我可以更好地表达我的需要: 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')

在我的模型的干净方法中,我想要一些具有这种逻辑的东西(这是伪代码):

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)

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

您需要显式声明应该为非空的字段,否则您将循环遍历与您的清理方法无关的字段,例如 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)