如何在 django 中使用模型清理方法并遍历字段
Posted
技术标签:
【中文标题】如何在 django 中使用模型清理方法并遍历字段【英文标题】:How to use model clean method in django and iterate over fields 【发布时间】:2020-01-30 19:54:13 【问题描述】:我问了一个问题,我读了一点,现在可以更好地表达我的需要: 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_ielts
是True
甚至没有填写一个字段,我会收到错误消息。如果has_ielts
是False
,则应保存具有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 方法中,我想要一些具有这种逻辑的东西(这是伪代码):
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.updatestr(field_name): msg
raise ValidationError(my_dic)
我该怎么做? 如何在模型级别获得与我的模型表单相同的结果?
【问题讨论】:
您需要明确地逐一检查 4 个字段(也在您的表单中),因为您只对以ielts
开头的字段感兴趣。包含其他字段是不好的编码。 if not ielts_listening: raise ValidationError(...); ...
.
我希望有一个可重用的代码用于其他模型,如 GRE、GMAT、IBT 等,在我当前的模型表单中,我正在遍历所有字段并更改其中一个。在拥有可重用代码的同时,应该有一种简洁的方法。这没有帮助吗? :for field in self._meta.fields:
但其中包括“id”、“student”等字段以及您稍后添加的其他字段。您可以将需要非空的字段列表一起定义为类属性并循环浏览该列表。不这样做会给使用您的模型的其他开发人员带来不可预测的结果。
@Daniel 我遇到了与此问题相关的问题,可在此处找到:***.com/questions/58254333/…
【参考方案1】:
您需要显式声明应为非空的字段,否则您将循环浏览与您的 clean 方法无关的字段,例如 id
和 student
。有人可能想稍后添加一个非强制性字段,并想知道为什么会引发验证错误。
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)
【讨论】:
这是 python 实际访问对象属性(和方法)的方法:getattr(self, "ielts_reading")
与 self.ielts_reading
相同。请参阅this question 了解更多信息。
例如,Django 使用它来清理您定义 clean_FOO
方法的各个字段:getattr(self, f"clean_field_name")()
将实际获取该方法并调用它(由于 ()
)
我不明白你的第一个问题。但是,是的,您在模型中进行的任何验证都不需要在模型表单中进行。通常,首先要开始对模型进行验证。如果此时的业务逻辑需要您执行额外的验证,或者如果您需要使用模型中不可用的变量进行验证,例如当前用户(模型验证中没有请求),您可以在模型表单中添加验证。
在抽象类中定义non_empty_fields = []
,并在每个子类中覆盖它。但是这样你就不必重复 clean()
方法了。
然后检查if getattr(self, field_name) is None
或if getattr(self, field_name) in [None, False, '']
而不是检查真实性。以上是关于如何在 django 中使用模型清理方法并遍历字段的主要内容,如果未能解决你的问题,请参考以下文章