Django 模型:使用来自同一 table 的 2 个外键时如何避免引用同一记录

Django model: How to avoid referencing the same record when using with 2 foreign keys from the same table

我有两个如下所示的 Django 模型:

class Team(models.Model):
    name = models.CharField(max_length=30)
    ...


class Game(models.Model):
    teamA = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamA')
    teamB = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamB')
    ....

Game 模型有 2 个指向 Team 模型的外键。

当然,一个队不可能和自己比赛,所以我想防止teamA和teamB在DB中引用同一条记录。

所以你不能创建这样的游戏:

Game.objects.create(teamA=ChicagoBulls, teamB=ChicagoBulls)

最好的方法是什么?

您可以在 .clean() method [Django-doc], and also at the database level with a CheckConstraint [Django-doc] 中实施约束(但并非所有数据库都会强制执行):

from django.core.exceptions import ValidationError
from django.db.models import F, Q

class Game(models.Model):
    teamA = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamA')
    teamB = models.ForeignKey(Team, on_delete=CASCADE, related_name='teamB')
    # …
    
    def clean(self, *args, **kwargs):
        if <b>self.teamA_id == self.teamB_id</b>:
            raise ValidationError('The two teams should be different')
        super().clean(*args, **kwargs)

    class Meta:
        constraints = [
            models.CheckConstraint(
                <b>check=~Q(teamA=F('teamB'))</b>,
                name='different_teams'
            )
        ]

使用模型层创建对象时,.clean() 方法 检查。但是,当您通过 ModelForm [Django-doc].

创建 Game 时,它会被验证

您可能还想使 Teamname 唯一,这样就不能有两个同名的团队:

class Team(models.Model):
    name = models.CharField(max_length=30<b>, unique=True</b>)
    # …