class Question(models.Model):
…
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE, related_name=“choices”)
The choice model is TabularInline with Question on admin.
When saving this form, want to add validation check that if no. of choices is less than 2, it should raise form Validation error. Ideas on how can I do it?
When a django form is saved, it goes through a default cleaning/sanitation process to assure the saved fields meet the constraints set forth in the models.py file. By default, this function is called ‘clean’ inside a custom form class.
For example:
class CustomForm(forms.ModelForm):
def clean(self):
# do your form validation here
class Meta:
...
If you want to assure the number of choices cannot be less than two, you can write a custom clean function that does the server-side validation for you.
class CustomForm(forms.ModelForm):
def clean_choices(self):
# a clean function for each form field is automatically generated, you just have to override it
choices = self.cleaned_data['choices']
if NUM_OF_CHOICES < 2:
raise forms.ValidationError(...)
return choices
class Meta:
...
Hope this helps
class QuestionForm(forms.ModelForm):
def clean_choices(self):
…
Tried this already but doesn’t work. Debugger doesn’t come up there.
Maybe because choices is not a field of Question model but rather a related name to Choice model.
Flow which I’ve noticed - Question is created first, then for every choice Choice model is called and a backlinking to Question is created.
If that’s the case, I would suggest looking into how to override the init function of the class you’re using. You should be able to prepopulate the choices of this form field you’re using. From there, once you render this field into your template, you can grab the submitted data through the GET or POST request dictionary and apply update your models accordingly. Not on a computer right now so I can’t easily post examples.
You referenced using the admin in your first post - have you specified your custom form in your ModelAdmin specification? (It might be best if you posted your admin.py file for these two classes.)
Also, when posting code here, please enclose it between lines consisting only of three backtick (`) characters. In other words, you’ll have a line of ```, followed by your code, followed by another line of ```. Make sure you use the backtick - ` and not the apostrophe - ’
class ChoiceAdmin(admin.TabularInline):
model = Choice
class QuestionForm(forms.ModelForm):
class Meta:
model = Question
fields = '__all__'
def clean_choices(self):
# do something
class QuestionAdmin(admin.ModelAdmin):
inlines = [ChoiceAdmin, ]
form = QuestionForm
This is an interesting issue. The function clean_<fieldname>
isn’t going to do you any good, because the inline formset is not a field in that form. It’s an instance of a model formset. There is also the issue that the base class needs to be saved before the formset can be saved because the formset needs the base model pk before those instances can be saved.
You could try working along these lines -
in admin.py:
class ChoiceAdmin(admin.TabularInline):
model = Choice
formset = forms.MyInlineFormSet
in forms.py
class MyInlineFormSet(forms.BaseInlineFormSet):
def clean(self):
super().clean()
number_of_entries = len(self.cleaned_data) - len(self.deleted_forms)
if number_of_entries < 2:
# Do something because not enough entries are present
What I don’t know at this point is whether or not the base class has been saved.
Ken
1 Like
Thanks a lot Ken, that worked !!!