假设我有这两个模型:
class Distribution(models.Model):
name = models.CharField(max_length=32)
class Component(models.Model):
distribution = models.ForeignKey(Distribution)
percentage = models.IntegerField()
我正在使用一个简单的TabularInline
在Component
管理员表单中显示Distribution
:
class ComponentInline(admin.TabularInline):
model = Component
extra = 1
class DistributionAdmin(admin.ModelAdmin):
inlines = [ComponentInline]
因此,我的目标是在保存之前验证Component
总和的所有Distribution
的百分比是否为100。听起来很简单,所以我做了:
# ... 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%')
但是这永远不会起作用,因为在Django中所有对象都是在保存其外键或many2many相关对象之前保存的,这不是一个缺陷,它有一个原因:它不能先保存相关对象,因为对象它们相关的还没有定义id
(id
是None
,直到对象首次在DB中保存。)
我确信我不是第一个遇到这个问题的人。那么,有没有办法完成我想要做的事情?我想的可能是使用TabularInline
或ModelAdmin
...
答案 0 :(得分:3)
如果您很乐意将验证从模型转移到内联formset,那么这是一个(未经测试的)想法:
子类BaseInlineFormSet
并覆盖clean方法以检查百分比的总和。
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%')
然后在ComponentInline
。
class ComponentInline(admin.TabularInline):
model = Component
extra = 1
formset = ComponentInlineFormSet