Django предотвращает дублирование двух внешних ключей в одной модели
У меня есть два поля внешнего ключа, которые указывают на одну и ту же модель. Я хотел бы предотвратить, чтобы они имели одинаковое значение. Вот мой код, который не работает
class Match(models.Model):
team_a = models.ForeignKey(Team, related_name='team_a', on_delete=models.CASCADE)
team_b = models.ForeignKey(Team, related_name='team_b', on_delete=models.CASCADE)
match_date_time = models.DateTimeField(validators=[validate_matchdate])
winner = models.CharField(choices=CHOICES, max_length=50, blank=True, null=True)
def clean(self):
direct = Match.objects.filter(team_a = self.team_a, team_b=self.team_b)
reverse = Match.objects.filter(team_a = self.team_b, team_b=self.team_a)
if direct.exists() & reverse.exists():
raise ValidationError('A team cannot be against itself')
.clean() метод на самом деле является методом формы. Поэтому, если вы хотите обрабатывать валидацию внутри формы, вам нужно сначала создать свою собственную форму. Если вы хотите выполнить валидацию внутри модели, вы можете использовать метод .save() или использовать для этого сигналы django.
class Match(models.Model):
team_a = models.ForeignKey(Team, related_name='team_a', on_delete=models.CASCADE)
team_b = models.ForeignKey(Team, related_name='team_b', on_delete=models.CASCADE)
match_date_time = models.DateTimeField(validators=[validate_matchdate])
winner = models.CharField(choices=CHOICES, max_length=50, blank=True, null=True)
def save(self, *args, **kwargs):
if self.team_a != self.team_b:
return super().save(*args, **kwargs)
return # or raise whatever
Вы можете добавить CheckConstraint
[Django-doc], чтобы база данных обеспечивала выполнение этого:
from django.db.models import F, Q
class Match(models.Model):
team_a = models.ForeignKey(
Team, related_name='matches_as_a', on_delete=models.CASCADE
)
team_b = models.ForeignKey(
Team, related_name='matches_as_b', on_delete=models.CASCADE
)
match_date_time = models.DateTimeField(validators=[validate_matchdate])
winner = models.CharField(
choices=CHOICES, max_length=50, blank=True, null=True
)
class Meta:
constraints = [
models.CheckConstraint(
check=~Q(team_a=F('team_b')), name='not_play_against_itself'
)
]