相关对象的Django模型约束

时间:2019-03-19 13:41:13

标签: python django django-models

我为模型提供了以下代码:

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模型的activityTagBinding字段具有相同的用户。我尝试做的事情:

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函数内部使用联接。同样,SubqueryOuterRef对我不起作用,因为未注册查询中引用的模型。

有什么方法可以使用新语法而不使用原始SQL来实现此约束?

更新

似乎某些SQL后端不支持约束定义中的联接,所以现在的问题是:甚至有可能在关系数据库中实现此行为吗?

1 个答案:

答案 0 :(得分:2)

在Postgres中,有两种类型的约束(除了唯一和外键约束之类的约束之外),CHECK CONSTRAINTS和EXCLUDE约束。

检查约束只能应用于单个行。

排除约束只能应用于单个表。

您将无法使用这两个方法来执行所需的约束,该约束会越过表格边界以确保一致性。

您可以使用基于触发器的约束,该约束可以执行其他查询以验证数据。

例如,您可以在各种表上具有BEFORE INSERT或UPDATE触发器,以检查用户是否匹配。我有一些类似的代码可在相同的自相关树代码上运行,以确保父级和子级都具有相同的“类别”。

在这种情况下,这将有些棘手,因为您需要某种机制来阻止检查,直到所有涉及的表都已更新。