Django Admin - Custom clean method for a model with foreignkey field

django-1.4, django-admin, django-forms, django-models

Solution

Ok, I finally found a way.

Just to clarify, I want to validate that the sum of all sections' crowd capacity doesn't exceed total arena crowd capacity.

Final solution is (in admin.py):

class SectionFormSet(forms.models.BaseInlineFormSet):
    def clean(self):
        if any(self.errors):
            return
        capacity = 0
        for f in self.forms:
            try:
                capacity += f.cleaned_data['crowd_capacity']
                if capacity > f.cleaned_data['arena'].crowd_capacity:
                    raise ValidationError('The sum of all sections crowd capacity '
                                              'exceeds arena crowd capacity')
            except KeyError:
                # in case of empty form
                pass


class SectionInline(admin.StackedInline):
    model = Section
    formset = SectionFormSet

class ArenaAdmin(admin.ModelAdmin):
    inlines = [
        SectionInline,
    ]

Thats it, no change to models. Works like a charm :)

Problem

Consider following models: ``` class Arena(models.Model): crowd_capacity = models.PositiveInteger() # more fields here class Section(models.Model): name = models.CharField(max_length=10) crowd_capacity = models.PositiveInteger() arena = models.ForeignKey(Arena, related_name='sections') ``` admin.py : ``` class SectionInline(admin.StackedInline): model = Section fk_name = 'arena' extra = 1 class ArenaAdmin(admin.ModelAdmin): inlines = [ SectionInline, ] ``` I want to add a validation method to check that the sum of all section.crowd_capacity doesn't exceeds total arena.crowd_capacity. At first i wanted to write a custom SectionFormSet with clean method, but then i didn't see how to get arena.crowd_capacity. I also tried to add clean method to Arena, it does show a nice red validation error but doesn't let fix the problem. Looks like Arena clean method runs after all sections were saved, and changing section.crowd_capacity and w.e section had the problem has no effect. The validation method i tried: ``` def clean(self): super(Arena, self).clean() capacity = 0 for s in self.sections.all(): capacity += s.crowd_capacity if capacity > self.crowd_capacity: raise ValidationError('The sum of all sections crowd capacity ' 'exceeds arena crowd capacity') ```

Original source