如果模型表单排除了某些字段,当模型具有干净的方法时如何处理模型表单的验证? [英] How to handle the validation of the model form when the model has a clean method if the model form excluded some fields?

查看:16
本文介绍了如果模型表单排除了某些字段,当模型具有干净的方法时如何处理模型表单的验证?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个模型:

class IeltsExam(Model):

    student = OneToOneField(Student, on_delete=CASCADE)
    has_taken_exam = BooleanField(default=False,)
    listening = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    reading = FloatField(choices=SCORE_CHOICES, null=True, blank=True, )
    exam_date = DateField(null=True, blank=True, )

    non_empty_fields = 
        {
            'listening': 'please enter your listening score',
            'reading': 'please enter your reading score',
            'exam_date': 'please specify your exam date',
        }

    def clean(self):
        errors = {}
        if self.has_taken_exam:
            for field_name, field_error in self.non_empty_fields.items():
                if getattr(self, field_name) is None:
                    errors[field_name] = field_error
        if errors:
            raise ValidationError(errors)

并拥有这个模型

class IeltsExamForm(ModelForm):

    class Meta:
        model = IeltsExam
        fields = ('has_taken_exam', 'listening', 'reading', )

当我在模板中提交此表单时,出现以下错误:

when I submit this form in template, I get the below error:

ValueError at /
'ExamForm' has no field named 'exam_date'.

During handling of the above exception ({'listening': ['please enter your listening score'], 'reading': ['please enter your reading score'], 'exam_date': ['please specify your exam date']}), another exception occurred:

错误发生在我验证表单的地方.我的数据库逻辑是这样的,我需要有一个exam_date 字段,如果检查了has_taken_exam,它应该是强制性的.但是,在 ExamForm 中,出于业务原因,我不需要exam_date.我怎么能告诉 ExamForm 对考试日期视而不见,因为我没有保存 modelform 实例?

The error happens in my view where I am validating the form. My database logic is such that I need to have an exam_date field and it should be mandatory to fill if has_taken_exam is checked. However, in ExamForm, for business reasons, I do not need the exam_date. How can I tell ExamForm to turn a blind eye to the exam_date, as I am not saving the modelform instance?

推荐答案

ModelForm 被初始化后,它有一个 instance 属性,它是模型实例,clean() 将被调用.因此,如果您从实例的 non_empty_fields 字典中删除 exam_date,它将不会在 clean 中使用它:

After the ModelForm is initialised, it has an instance attribute which is the model instance on which clean() will be called. So if you remove exam_date from the instance's non_empty_fields dictionary, it won't use it in clean:

class IeltsExamForm(ModelForm): 
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.instance.non_empty_fields.pop('exam_date')

您可以对 self._meta.exclude 中的每个字段执行此操作.

And you could do that for each field in self._meta.exclude.

然而,当这样做时,属性 non_empty_fields 不应该是一个类属性,而是一个实例属性.修改实例的 non_empty_fields 实际上修改了 class 属性(它是一个字典,所以它是可变的),这将产生意想不到的副作用(一旦删除,它就会为您创建的任何后续实例删除).更改您的模型以在 init 方法中设置属性:

However, when doing that, the attribute non_empty_fields should not be a class attribute but an instance property. Modifying the instance's non_empty_fields actually modifies the class attribute (it's a dictionary so it's mutable), which will have unintended side-effects (once removed, it's removed for any subsequent instance you create). Change your model to set the attribute in the init method:

class IeltsExam(Model):
    # ...
    # remove the class attribute non_empty_fields

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.non_empty_fields = { ... }

一般来说,如果您真的要保存模型,我建议您只使用 ModelForm,在这种情况下,类属性是更简洁的方法.如果您的表单不打算保存实际模型,那么与其执行所有这些操作,您不应该使用 ModelForm 而是使用 Form 并定义所有字段并清理形式本身.

In general, I would advise you to only use a ModelForm if you're actually going to save the model, in which case a class attribute is the cleaner approach. Instead of doing all this, if your form isn't going to save the actual model, you should not use a ModelForm but a Form and define all fields and cleaning in the form itself.

这篇关于如果模型表单排除了某些字段,当模型具有干净的方法时如何处理模型表单的验证?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆