Reputation: 445
I'm trying to validate my inline formset cost value's to make sure that it adds up to 100. The formset is returned 5 times so foreach the value should be added until 100 is hit. If it's more or less than that show an error & not allow the user to hit the create button. I'm trying to validated all the forms combined not each form value.
Models.py
class EstimatedBudgetForm(forms.ModelForm):
def clean(self):
# get forms that actually have valid data
count = 0
for percentage in self.cost:
try:
if percentage.cleaned_data:
count += percentage
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if count != 100:
raise forms.ValidationError('Percentage must equal 100%')
Views.py
EstimatedBudgetChildFormset = inlineformset_factory(
Project, EstimatedBudget, fields=('project', 'item', 'cost', 'time'), can_delete=False, form=EstimatedBudgetForm, extra=5, widgets={'item': forms.Select(attrs={'disabled': True})},
)
Upvotes: 3
Views: 640
Reputation: 21807
To perform validation for a formset one should override the clean
method of the formset (not the form). For an inline formset you need to inherit from BaseInlineFormSet
and use that (For more information see Overriding clean() on a ModelFormSet [Django docs]):
from django.forms import BaseInlineFormSet
class MyInlineFormset(BaseInlineFormSet):
def clean(self):
super().clean()
count = 0
for form in self.forms:
if not form.errors: # No need for a try-except, just check if the form doesn't have errors
count += form.cleaned_data['cost']
if count != 100: # This condition might not work if you are dealing with floating point numbers
raise forms.ValidationError('Percentage must equal 100%')
Next while making the formset, specify the formset
kwarg rather than form
:
EstimatedBudgetChildFormset = inlineformset_factory(
Project, EstimatedBudget, fields=('project', 'item', 'cost', 'time'), can_delete=False, formset=MyInlineFormset, extra=5, widgets={'item': forms.Select(attrs={'disabled': True})},
)
Upvotes: 6