3

次のような 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_playersa のメソッドで数値を検証します。このメソッドは呼び出されません。他の非 ManyToMany フィールドの同様のメソッドが呼び出されます。ModelFormTeamAdmin

  3. clean前述の方法で番号を検証しModelFormます。このメソッドが呼び出されますが、self.cleaned_data辞書には のエントリがありません'players'

このタイプの検証を達成する方法はありますか? 私は Django の専門家ではありませんので、当然のことをすべて実行したとは思わないでください。

4

1 に答える 1

5

formsetTeamPlayerInlineに を設定する必要があります。そして、そのフォーム セットの 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]
于 2013-09-20T21:52:25.040 に答える