Check inline strings before saving model

Let's say I have two models:

class Distribution(models.Model): name = models.CharField(max_length=32) class Component(models.Model): distribution = models.ForeignKey(Distribution) percentage = models.IntegerField() 

And I use a simple TabularInline to display Component inside the Distribution admin form:

 class ComponentInline(admin.TabularInline): model = Component extra = 1 class DistributionAdmin(admin.ModelAdmin): inlines = [ComponentInline] 

So, my goal is to confirm if the percentages of the entire Component of the Distribution sum 100 are before saving. It sounds simple, so I did:

 # ... Inside the Distribution model def clean(self): # Sum of components must be 100 total_sum = sum(comp.percentage for comp in self.component_set.all()) if total_sum != 100: raise ValidationError('Sum of components must be 100%') 

But this will never work, because in Django all objects are saved before saving the foreign key or many other related objects, this is not a drawback, it has a reason: it cannot save the related objects first, because the object to which they are connected is not yet defined id ( id is None until the object is saved for the first time in the database).

I am sure that I am not the first to encounter this problem. So, is there a way to accomplish what I'm trying to do? I was thinking maybe hacking an administrator using TabularInline or ModelAdmin ...?

+6
source share
1 answer

Here's a (untested) idea if you are happy to port validation from a model to an inline set of forms:

Subclass BaseInlineFormSet and override the clean method to check the amount of interest.

 from django.forms.models import BaseInlineFormSet from django.core.exceptions import ValidationError class ComponentInlineFormSet(BaseInlineFormSet): def clean(self): """Check that sum of components is 100%""" if any(self.errors): # Don't bother validating the formset unless each form is valid on its own return total_sum = sum(form.cleaned_data['percentage'] for form in self.forms) if total_sum != 100: raise ValidationError('Sum of components must be 100%') 

Then use your built-in ComponentInline in ComponentInline .

 class ComponentInline(admin.TabularInline): model = Component extra = 1 formset = ComponentInlineFormSet 
+3
source

Source: https://habr.com/ru/post/908063/


All Articles