Django模型:如何避免在使用来自同一个表的2个外键时引用相同的记录
Posted
技术标签:
【中文标题】Django模型:如何避免在使用来自同一个表的2个外键时引用相同的记录【英文标题】:Django model: How to avoid referencing the same record when using with 2 foreign keys from the same table 【发布时间】:2020-10-21 05:26:54 【问题描述】:我有两个看起来像这样的 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)
最好的方法是什么?
【问题讨论】:
【参考方案1】:您可以在.clean()
method [Django-doc] 中实现约束,也可以在数据库级别使用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 self.teamA_id == self.teamB_id:
raise ValidationError('The two teams should be different')
super().clean(*args, **kwargs)
class Meta:
constraints = [
models.CheckConstraint(
check=~Q(teamA=F('teamB')),
name='different_teams'
)
]
.clean()
方法在您使用模型层创建对象时不检查。但是,当您通过ModelForm
[Django-doc] 创建Game
时,它会得到验证。
您可能还想让Team
的name
唯一,这样就不能有两个同名的团队:
class Team(models.Model):
name = models.CharField(max_length=30, unique=True)
# …
【讨论】:
以上是关于Django模型:如何避免在使用来自同一个表的2个外键时引用相同的记录的主要内容,如果未能解决你的问题,请参考以下文章
Django - 使用表单集在不通过表的情况下建立 2 个模型之间的多对多关系
Django Python - 如何在一个 HTML 模板中显示来自不同表的信息