保存模型前验证内联

时间:2012-02-09 17:29:36

标签: python django foreign-keys

假设我有这两个模型:

class Distribution(models.Model):
    name = models.CharField(max_length=32)

class Component(models.Model):
    distribution = models.ForeignKey(Distribution)
    percentage = models.IntegerField()

我正在使用一个简单的TabularInlineComponent管理员表单中显示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相关对象之前保存的,这不是一个缺陷,它有一个原因:它不能先保存相关对象,因为对象它们相关的还没有定义ididNone,直到对象首次在DB中保存。)

我确信我不是第一个遇到这个问题的人。那么,有没有办法完成我想要做的事情?我想的可能是使用TabularInlineModelAdmin ...

的管理员黑客攻击

1 个答案:

答案 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

中使用您的内联formset
class ComponentInline(admin.TabularInline):
    model = Component
    extra = 1
    formset = ComponentInlineFormSet