4

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')
Neara
  • 3,693
  • 7
  • 29
  • 40

1 Answers1

4

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 :)

Neara
  • 3,693
  • 7
  • 29
  • 40