在Django admin中验证ManyToManyField项目(使用中间模型)的数量

时间:2013-09-20 21:17:49

标签: python django validation django-admin django-forms

我有一些看起来像这样的Django模型(这不是我的确切代码,但是具有相同结构的更简单的例子):

class Player(models.Model):
    # Some fields here.
    pass

class Team(models.Model):
    players = models.ManyToManyField(Player, through='TeamPlayer')

class TeamPlayer(models.Model):
    team = models.ForeignKey(Team)
    player = models.ForeignKey(Player)
    some_other_field = models.BooleanField()

我正在使用through机制,因为我的链接表上有额外的列。

我的管理类看起来像这样(注意我使用内联管理员添加玩家):

class TeamPlayerInline(admin.TabularInline):
    model = TeamPlayer
    max_num = 11
    extra = 11

class TeamAdmin(admin.ModelAdmin):
    inlines = [TeamPlayerInline]

admin.site.register(Team, TeamAdmin)

问题:我的问题是,在我的管理员中,我想确认一个团队只有11名玩家。任何更少的都应该导致错误。我怎么能这样做?

这些是我尝试过的东西以及它们不起作用的原因:

  1. 验证clean模型的Team方法中的玩家数量。这不起作用,因为玩家还没有被保存,所以对于一个新对象总是没有玩家。

  2. 验证clean_players使用的ModelForm TeamAdmin方法中的数字。永远不会调用此方法。其他非ManyToMany字段的类似方法也会被调用。

  3. 验证上述clean的{​​{1}}方法中的数字。调用此方法,但ModelForm字典没有self.cleaned_data的条目。

  4. 我有什么想法可以实现这种类型的验证?我不是一个Django专家,所以不要以为我必须完成一切应该是显而易见的事情。

1 个答案:

答案 0 :(得分:4)

您需要在TeamPlayerInline上设置formset。并覆盖该表单集中的clean方法。例如:

from django.forms.models import BaseInlineFormSet

class TeamPlayerFormset(BaseInlineFormSet):
    def clean(self):
        """Check that exactly 11 players are entered."""
        super(TeamPlayerFormset, self).clean()

        if any(self.errors):
            return

        count = 0
        for cleaned_data in self.cleaned_data:
            if cleaned_data and not cleaned_data.get('DELETE', False):
                count += 1
        if count != 11:
            raise forms.ValidationError('You must enter 11 team players.')


class TeamPlayerInline(admin.TabularInline):
    model = TeamPlayer
    max_num = 11
    extra = 11
    formset = TeamPlayerFormset


class TeamAdmin(admin.ModelAdmin):
    inlines = [TeamPlayerInline]