ダニ・エレーラからはすでに素晴らしい答えがありますが、さらに詳しく説明したいと思います。
2番目のオプションで説明したように、OPで必要なソリューションは、デザインを変更し、2つの一意の制約をペアで実装することです。バスケットボールの試合との類似は、非常に実用的な方法で問題を示しています。
バスケットボールの試合の代わりに、フットボール(またはサッカー)ゲームの例を使用します。フットボールの試合(私はそれと呼んでいますEvent
)は2つのチーム(私のモデルではチームはCompetitor
)によって行われます。これは多対多の関係(m:n
)でありn
、この特定のケースでは2つに制限されているため、原則は無制限の数に適しています。
モデルは次のようになります。
class Competitor(models.Model):
name = models.CharField(max_length=100)
city = models.CharField(max_length=100)
def __str__(self):
return self.name
class Event(models.Model):
title = models.CharField(max_length=200)
venue = models.CharField(max_length=100)
time = models.DateTimeField()
participants = models.ManyToManyField(Competitor)
def __str__(self):
return self.title
イベントには次のものがあります。
- タイトル:カラバオカップ、第4ラウンド、
- 会場:アンフィールド
- 時間:2019年10月30日、19:30 GMT
- 参加者:
- 名前:リバプール、都市:リバプール
- 名前:アーセナル、都市:ロンドン
次に、問題から問題を解決する必要があります。Djangoは多対多の関係を持つモデル間に中間テーブルを自動的に作成しますが、カスタムモデルを使用してフィールドを追加することもできます。私はそのモデルを呼び出しますParticipant
:
クラスParticipant(models.Model):
ロール=(
(「H」、「ホーム」)、
(「V」、「訪問者」)、
)
event = models.ForeignKey(Event、on_delete = models.CASCADE)
competitor = models.ForeignKey(Competitor、on_delete = models.CASCADE)
role = models.CharField(max_length = 1、choices = ROLES)
クラスMeta:
unique_together =(
( 'イベント'、 'ロール')、
(「イベント」、「競合他社」)、
)
def __str __(self):
'{}-{}'を返します。format(self.event、self.get_role_display())
にManyToManyField
は、through
中間モデルを指定できるオプションがあります。モデルでそれを変更しましょうEvent
:
class Event(models.Model):
title = models.CharField(max_length=200)
venue = models.CharField(max_length=100)
time = models.DateTimeField()
participants = models.ManyToManyField(
Competitor,
related_name='events', # if we want to retrieve events for a competitor
through='Participant'
)
def __str__(self):
return self.title
一意の制約により、イベントごとの競合者の数は自動的に2つに制限されます(ホームと訪問者の 2つの役割しかないため)。
特定のイベント(サッカーゲーム)では、ホームチームとビジターチームはそれぞれ1つだけです。クラブ(Competitor
)は、ホームチームまたはビジターチームとして表示されます。
これらすべてを管理者でどのように管理しますか?このような:
from django.contrib import admin
from .models import Competitor, Event, Participant
class ParticipantInline(admin.StackedInline): # or admin.TabularInline
model = Participant
max_num = 2
class CompetitorAdmin(admin.ModelAdmin):
fields = ('name', 'city',)
class EventAdmin(admin.ModelAdmin):
fields = ('title', 'venue', 'time',)
inlines = [ParticipantInline]
admin.site.register(Competitor, CompetitorAdmin)
admin.site.register(Event, EventAdmin)
Participant
インラインとしてをに追加しましたEventAdmin
。新規作成時にEvent
、ホームチームとビジターチームを選択できます。このオプションでmax_num
はエントリの数が2に制限されるため、イベントごとに追加できるチームは2つまでです。
これは、さまざまなユースケースに合わせてリファクタリングできます。私たちのイベントは、水泳競技であり、代わりに自宅と訪問者の、私達は私達はちょうどリファクタリング1〜8レーンを持っているとしましょうParticipant
:
class Participant(models.Model):
ROLES = (
('L1', 'lane 1'),
('L2', 'lane 2'),
# ... L3 to L8
)
event = models.ForeignKey(Event, on_delete=models.CASCADE)
competitor = models.ForeignKey(Competitor, on_delete=models.CASCADE)
role = models.CharField(max_length=1, choices=ROLES)
class Meta:
unique_together = (
('event', 'role'),
('event', 'competitor'),
)
def __str__(self):
return '{} - {}'.format(self.event, self.get_role_display())
この変更により、次のイベントを作成できます。
水泳選手はヒートで1回しか出現できず、レーンはヒートで1回しか占有できません。
コードをGitHub:https : //github.com/cezar77/competitionに配置します。
繰り返しになりますが、クレジットはすべてdani herreraに送られます。この回答が読者にいくつかの付加価値を提供することを願っています。