Büyük zaten var cevabı gelen dani herrera ancak ben daha bunun üzerinde durmak istiyoruz.
İkinci seçenekte açıklandığı gibi, OP'nin gerektirdiği çözüm tasarımı değiştirmek ve iki benzersiz kısıtlamayı çift olarak uygulamaktır. Basketbol maçlarıyla analoji, sorunu çok pratik bir şekilde göstermektedir.
Basketbol maçı yerine futbol (veya futbol) oyunlarında örnek kullanıyorum. Bir futbol oyunu (buna ben diyorum Event
) iki takım tarafından oynanır (modellerimde bir takım Competitor
). Bu, çoktan çoğa bir ilişkidir ( m:n
), n
bu özel durumda iki ile sınırlıdır, ilke sınırsız sayıda için uygundur.
Modellerimiz şöyle görünüyor:
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
Bir olay şunlar olabilir:
- Başlık: Carabao Kupası, 4. tur,
- mekan: Anfield
- zaman: 30. Ekim 2019, 19:30 GMT
- katılımcılar:
- isim: Liverpool, şehir: Liverpool
- isim: Arsenal, şehir: Londra
Şimdi sorunu sorudan çözmek zorundayız. Django, çoktan çoğa ilişkisi olan modeller arasında otomatik olarak bir ara tablo oluşturur, ancak özel bir model kullanabilir ve daha fazla alan ekleyebiliriz. Ben buna model diyorum Participant
:
sınıf Katılımcısı (modeller. Model):
ROLLER = (
('H', 'Ev'),
('V', 'Ziyaretçi'),
)
event = models.ForeignKey (Etkinlik, on_delete = models.CASCADE)
competitor = models.ForeignKey (Rakip, on_delete = models.CASCADE)
role = models.CharField (max_length = 1, seçenekler = ROLES)
Meta sınıfı:
unique_together = (
('etkinlik', 'rol'),
('etkinlik', 'rakip'),
)
def __str __ (öz):
dönüş '{} - {}'. biçimi (self.event, self.get_role_display ())
Bu ManyToManyField
, through
ara modeli belirlememize izin veren bir seçeneğe sahiptir . Modelde bunu değiştirelim 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
Benzersiz kısıtlamalar artık etkinlik başına yarışmacı sayısını otomatik olarak ikiyle sınırlayacaktır (çünkü yalnızca iki rol vardır: Ev ve Ziyaretçi ).
Belirli bir etkinlikte (futbol oyunu) sadece bir ev sahibi takım ve sadece bir ziyaretçi ekibi olabilir. Bir kulüp ( Competitor
) ev sahibi takım veya ziyaretçi takımı olarak görünebilir.
Tüm bunları şimdi yöneticide nasıl yönetiriz? Bunun gibi:
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
Olarak satır içi olarak ekledik EventAdmin
. Yeni Event
yarattığımızda ev sahibi takımı ve ziyaretçi ekibini seçebiliriz. Seçenek max_num
, giriş sayısını 2 ile sınırlar, bu nedenle etkinlik başına 2'den fazla ekip eklenemez.
Bu, farklı kullanım durumları için yeniden düzenlenebilir. En Bizim olaylar yüzme yarışmaları ve yerine ev ve ziyaretçinin, biz Biz sadece planı ayrı 1'den 8'e şerit var diyelim 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())
Bu değişiklikle şu etkinliğe sahip olabiliriz:
Bir yüzücü ısıda sadece bir kez görünebilir ve bir şerit ısıda sadece bir kez işgal edilebilir.
Kodu GitHub'a koydum: https://github.com/cezar77/competition .
Yine, tüm krediler dani herrera'ya gidiyor. Umarım bu cevap okuyuculara bir miktar katma değer sağlar.