Reputation: 2436
I asked a question and, as I have read a little, I now can better express what I need: How to do model level custom field validation in django?
I have this model:
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, )
and have this model form:
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
What I am doing here is that checking if has_ielts
is True
, then all other fields should be filled. If has_ielts
is True
and even one field is not filled, I get an error. If has_ielts
is False
, an object with has_ielts=False
and all other fields Null
should be saved. I now want to do it on the model level:
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
and have this model form:
class StudentIeltsForm(ModelForm):
class Meta:
model = StudentIelts
exclude = ('student')
In the clean method of my model I want something with this logic(this is psedue code):
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)
How can I do this?
How can I get the same result as my modelform but at the model level?
Upvotes: 0
Views: 2820
Reputation: 20692
You need to explicitly declare the fields that should be non-empty, otherwise you're cycling through fields that are not related to your clean method, like id
and student
. Someone might want to add a field later one that's not mandatory and wonder why it raises a validation error.
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)
Upvotes: 1