Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django admin validation for inline form which rely on the total of a field between all forms

Forgive me if this has been answered before, I couldn't find an answer where the validation depended on the aggregate of inline forms.

Little background: I'm doing a site for an insurance broker which has 'Policies' and a 'Total Commission' of that policy. There are also 'Resellers' which are added to the 'Policy' along with a commission which goes to them (can have any number of resellers). The total commission between the resellers has to be less than the total commission.

I have an admin.ModelForm for a policy, and below I have a admin.InlineTabular which can have multiple resellers through the 'Add' button and this all works perfectly.

However, I can't seem to figure out how to do validation on them, so that I can basically add up all the commissions and then if it is greater than the total commission throw a ValidationError.

I've tried clean() but don't know how to access the InlineTabular cleaned data if it is even available!

Thanks in advance for any help!

Thomas

like image 943
user569888 Avatar asked Jan 19 '11 13:01

user569888


People also ask

Which method has a form instance which runs validation routines for all its fields?

The run_validators() method on a Field runs all of the field's validators and aggregates all the errors into a single ValidationError .

How do I validate fields in Django?

Django forms submit only if it contains CSRF tokens. It uses uses a clean and easy approach to validate data. The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class. It returns True if data is valid and place all data into a cleaned_data attribute.

How do you exclude a specific field from a ModelForm?

Set the exclude attribute of the ModelForm 's inner Meta class to a list of fields to be excluded from the form.

What is Inlines in Django admin?

The admin interface is also customizable in many ways. This post is going to focus on one such customization, something called inlines. When two Django models share a foreign key relation, inlines can be used to expose the related model on the parent model page. This can be extremely useful for many applications.


1 Answers

I know the question was asked a long time ago, but since I struggled with the same problem, I think it might be usefull.

The key here is to define a custom formset to embed into the tabular admin form, then to override the formset clean's method.

Here's an example : a composition is made of composition_elements, each composition_element has a percent field, and I want to validate that the total percent is equal to 100.

from django import forms
from django.forms.models import BaseInlineFormSet
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from django.contrib import admin
from .models import Composition, CompositionElement

class CompositionElementFormSet(BaseInlineFormSet):
    '''
    Validate formset data here
    '''
    def clean(self):
        super(CompositionElementFormSet, self).clean()

        percent = 0
        for form in self.forms:
            if not hasattr(form, 'cleaned_data'):
                continue
            data = form.cleaned_data
            percent += data.get('percent', 0)

        if percent != 100:
            raise ValidationError(_('Total of elements must be 100%%. Current : %(percent).2f%%') % {'percent': percent})

class CompositionElementAdmin(admin.TabularInline):
    model = CompositionElement
    formset = CompositionElementFormSet

class CompositionAdmin(admin.ModelAdmin):
    inlines = (CompositionElementAdmin,)

admin.site.register(Composition, CompositionAdmin)
like image 54
Thibault J Avatar answered Nov 02 '22 19:11

Thibault J