Validate inlines before saving model

2024/10/6 22:32:16

Let's say I have these 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'm using a simple TabularInline to show Components inside the Distribution admin form:

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

So, my goal is to validate if the percentages of all the Components of the Distribution sum 100 before saving it. Sounds simple, so I did:

# ... Inside the Distribution model
def clean(self):# Sum of components must be 100total_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 work, because in Django all objects are saved before saving its foreign-key or many2many related objects, this is not a flaw, it has a reason: it cannot save the related objects first, because the object to which they are related doesn't have an id defined yet (id is None until the object is saved for the first time in the DB).

I'm sure I'm not the first guy to run into this issue. So, is there a way to accomplish what I'm trying to do? I was thinking maybe a admin hack using TabularInline or ModelAdmin ... ?

Answer

Here's an (untested) idea, if you're happy to move the validation from the model to the inline formset:

Subclass BaseInlineFormSet and override the clean method to check the sum of the percentages.

from django.forms.models import BaseInlineFormSet
from django.core.exceptions import ValidationErrorclass 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 ownreturntotal_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 inline formset in the ComponentInline.

class ComponentInline(admin.TabularInline):model = Componentextra = 1formset = ComponentInlineFormSet
https://en.xdnf.cn/q/70314.html

Related Q&A

Grouping and comparing groups using pandas

I have data that looks like:Identifier Category1 Category2 Category3 Category4 Category5 1000 foo bat 678 a.x ld 1000 foo bat 78 l.o …

Transform a 3-column dataframe into a matrix

I have a dataframe df, for example:A = [["John", "Sunday", 6], ["John", "Monday", 3], ["John", "Tuesday", 2], ["Mary", "Sunday…

python multiline regex

Im having an issue compiling the correct regular expression for a multiline match. Can someone point out what Im doing wrong. Im looping through a basic dhcpd.conf file with hundreds of entries such as…

OpenCV Python Bindings for GrabCut Algorithm

Ive been trying to use the OpenCV implementation of the grab cut method via the Python bindings. I have tried using the version in both cv and cv2 but I am having trouble finding out the correct param…

showing an image with Graphics View widget

Im new to qt designer and python. I want to created a simple project that I should display an image. I used "Graphics View" widget and I named it "graphicsView". I wrote these funct…

TemplateSyntaxError: settings_tags is not a valid tag library

i got this error when i try to run this test case: WHICH IS written in tests.py of my django application:def test_accounts_register( self ):self.url = http://royalflag.com.pk/accounts/register/self.c =…

Setting NLTK with Stanford NLP (both StanfordNERTagger and StanfordPOSTagger) for Spanish

The NLTK documentation is rather poor in this integration. The steps I followed were:Download http://nlp.stanford.edu/software/stanford-postagger-full-2015-04-20.zip to /home/me/stanford Download http:…

python variable scope in nested functions

I am reading this article about decorator.At Step 8 , there is a function defined as:def outer():x = 1def inner():print x # 1return innerand if we run it by:>>> foo = outer() >>> foo.…

How can I throttle Python threads?

I have a thread doing a lot of CPU-intensive processing, which seems to be blocking out other threads. How do I limit it?This is for web2py specifically, but a general solution would be fine.

get lastweek dates using python?

I am trying to get the date of the last week with python. if date is : 10 OCT 2014 meansIt should be print10 OCT 2014, 09 OCT 2014, 08 OCT 2014, 07 OCT 2014, 06 OCT 2014, 05 OCT 2014, 04 OCT 2014I trie…