如何在Django的多个ForeignKey字段中强制执行不同的值

jhc*_*jhc 6 python sql django django-models

我在Django中有以下模型:

from django.db import models

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


class Match(models.Model):                                                      
    team_home = models.ForeignKey(Team)                                                      
    team_visitors = models.ForeignKey(Team)                                                       
    league = models.CharField(max_length=200)                                                      
    date_played = models.DateField()  
Run Code Online (Sandbox Code Playgroud)

我们的想法是能够拥有一个"匹配"对象,该对象有两个团队参与某场比赛的比赛.一支球队自己打球真是太奇怪了.我怎么能保证team_home不等于team_visitors

Ali*_*ari 10

您可以在 Django 模型的 Meta 类中使用此 CheckConstraint:

class Meta:
    constraints = [
        models.CheckConstraint(
            check=~Q(team_home=F('team_visitors')),
            name='team_home_and_team_visitors_can_not_be_equal')
    ]
Run Code Online (Sandbox Code Playgroud)


Der*_*wok 5

这不能通过纯Django来完成.有一个添加CHECK约束的票:https://code.djangoproject.com/ticket/11964

为了确保team_home == team_visitors从未发生过的情况,您需要向依赖于数据库的表添加自定义约束.例如,在MySQL和PostgresQL中:

alter table myapp_match add constraint match_teams_not_equal check (team_home_id <> team_visitors_id);
Run Code Online (Sandbox Code Playgroud)

这将导致数据库在发生保存时引发完整性错误.请注意,还有一些数据库无法实现此类约束.

您可以team_home != team_visitors通过覆盖save方法来部分确保:

class Match(models.Model):
    ....
    def save(self, *args, **kwargs):
        if self.team_home == self.team_visitors:
            raise Exception('attempted to create a match object where team_home == team_visitors')
        super(Match, self).save(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

但是,有人可以直接修改数据库,或者update在Django中使用queryset,你仍然可以Match在其中使用对象team_home == team_visitor.

  • “CHECK”约束现在在 Django 2.2+ 中得到支持,作为模型元选项的一部分。 (3认同)