【发布时间】:2019-03-19 13:41:13
【问题描述】:
我有以下模型代码:
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 模型上编写数据库约束。此约束应检查 TagBinding 模型的 tag 和 activity 字段是否具有相同的用户。我试图做的事情:
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 后端不支持约束定义中的连接,所以现在的问题是:是否有可能在关系数据库中实现这种行为?
【问题讨论】:
-
为什么在 db 级别需要这个约束?
-
因为应尽可能将约束卸载到数据库,而不是在代码中强制执行。但是这种约束是必要的吗?我怀疑它可以通过不同的建模来避免,但我不能完全确定它。
-
@dan-klasson 当然,我可以在代码级别包含此逻辑,但我更愿意将此行为限制在可能的最低级别(特别是如果此行为在逻辑上适合此级别)。 @EndreBoth 我也在寻找另一个模型,但没有找到。我想出的所有解决方案都只是删除模型
Tag并在Activity模型中定义tags字段。但它会删除所有可以使用标签存储的其他数据。 -
建模确实有问题。您已经在 Activity 模型中有 ManyToMany 字段“标签”。这意味着给定的活动可以与许多标签相关联,因此可以与许多不同的用户相关联(假设标签有不同的用户)。在这种情况下,活动中的“用户”属性对我来说似乎没有多大意义。如果你想实现“绑定”,那么你不需要为此手动创建一个单独的表(Django 已经在幕后为你创建了 ManyToMany 字段)。
-
@arudzinska
user字段对于两个模型都是必需的,因为关系不是强制性的。可以有没有标签的活动和没有活动的标签,但它们都应该分配给特定用户。中间模型TagBinding被添加到示例中,因为它稍后用于约束定义。如果没有任何东西可以添加到中间模型中,则可以省略(如您所说)。
标签: python django django-models