我为模型提供了以下代码:
class Tag(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
class Activity(models.Model):
user = models.ForeignKey('auth.User', on_delete=models.CASCADE)
tags = models.ManyToManyField(Tag, through='TagBinding')
class TagBinding(models.Model):
tag = models.ForeignKey(Tag)
activity = models.ForeignKey(Activity)
我想使用新的Django 2.2语法在TagBinding
模型上编写数据库约束。此约束应检查tag
模型的activity
和TagBinding
字段具有相同的用户。我尝试做的事情:
class TagBinding(models.Model):
tag = models.ForeignKey(Tag)
activity = models.ForeignKey(Activity)
class Meta:
constraints = [
models.CheckConstraint(
name='user_equality',
check=Q(tag__user=F('activity__user')),
)
]
但是这不起作用,因为Django不允许在F
函数内部使用联接。同样,Subquery
和OuterRef
对我不起作用,因为未注册查询中引用的模型。
有什么方法可以使用新语法而不使用原始SQL来实现此约束?
似乎某些SQL后端不支持约束定义中的联接,所以现在的问题是:甚至有可能在关系数据库中实现此行为吗?
答案 0 :(得分:2)
在Postgres中,有两种类型的约束(除了唯一和外键约束之类的约束之外),CHECK CONSTRAINTS和EXCLUDE约束。
检查约束只能应用于单个行。
排除约束只能应用于单个表。
您将无法使用这两个方法来执行所需的约束,该约束会越过表格边界以确保一致性。
您可以使用基于触发器的约束,该约束可以执行其他查询以验证数据。
例如,您可以在各种表上具有BEFORE INSERT或UPDATE触发器,以检查用户是否匹配。我有一些类似的代码可在相同的自相关树代码上运行,以确保父级和子级都具有相同的“类别”。
在这种情况下,这将有些棘手,因为您需要某种机制来阻止检查,直到所有涉及的表都已更新。