保存模型前验证内联 [英] Validate inlines before saving model
问题描述
class Distribution(models.Model):
name = models .CharField(max_length = 32)
class组件(models.Model):
distribution = models.ForeignKey(Distribution)
percent = models.IntegerField()
我正在使用一个简单的 TabularInline
来显示组件
在分发
管理表单中:
class ComponentInline(admin.TabularInline):
model = Component
extra = 1
class DistributionAdmin(admin.ModelAdmin):
inlines = [ComponentInline]
所以,我的目标是验证所有
之前保存100。听起来很简单,所以我做了:分配
组件
#...分配模型内
def clean(self):
#组件总和必须为100
total_sum = sum(comp.percentage for comp in self.component_set.all())
如果total_sum!= 100:
raise ValidationError('组件总和必须为100%')
但是这不会工作,因为在Django中所有对象在保存其外键或许多2个相关对象之前被保存,这不是缺陷,它有一个原因:它不能先保存相关对象,因为它们相关的对象没有一个 id
定义( id
是无
直到对象第一次保存在DB中)
我相信我不是第一个遇到这个问题的人。那么,有没有办法完成我想要做的事情?我正在考虑使用 TabularInline
或 ModelAdmin
...?
这是一个(未经测试)的想法,如果您很乐意将验证从模型移动到内联表单集:
子类 BaseInlineFormSet
并覆盖clean方法来检查百分比之和。
导入BaseInlineFormSet
from django.core.exceptions import ValidationError
class ComponentInlineFormSet(BaseInlineFormSet):
def clean(self):
检查组件的总和是否为100%
如果有的话(self.errors):
#不要打扰验证表单,除非每个表单对于self.forms中的表单,
返回
total_sum = sum(form.cleaned_data ['percentage'])
如果total_sum!= 100:
raise ValidationError( 组件总和必须是100%')
然后在 ComponentInline
。
class ComponentInline(admin.TabularInline):
model = Component
extra = 1
formset = ComponentInlineFormSet
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 Component
s inside the Distribution
admin form:
class ComponentInline(admin.TabularInline):
model = Component
extra = 1
class DistributionAdmin(admin.ModelAdmin):
inlines = [ComponentInline]
So, my goal is to validate if the percentages of all the Component
s 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 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 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
... ?
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 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 inline formset in the ComponentInline
.
class ComponentInline(admin.TabularInline):
model = Component
extra = 1
formset = ComponentInlineFormSet
这篇关于保存模型前验证内联的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!