Django 如何在联接表上的两个外键之间强制执行数据库约束?

Django 如何在联接表上的两个外键之间强制执行数据库约束?,django,database,django-models,orm,model,Django,Database,Django Models,Orm,Model,我试图在联接表上的两个外键之间强制执行约束,但我不知道是否可以使用数据库来执行,或者是否应该通过我的应用程序或ORM来执行 这是我的桌子: Dataset Tag - Dataset: FK - name: string (eg: "park", "church", etc) Place - Dataset: FK - latitude - longitude PlaceTag (my join table) - Tag: FK - Place: FK - note: st

我试图在联接表上的两个外键之间强制执行约束,但我不知道是否可以使用数据库来执行,或者是否应该通过我的应用程序或ORM来执行

这是我的桌子:

Dataset

Tag
 - Dataset: FK
 - name: string (eg: "park", "church", etc)

Place
 - Dataset: FK
 - latitude
 - longitude

PlaceTag (my join table)
 - Tag: FK
 - Place: FK
 - note: string (eg: "this place is my favorite park")
我想强制每个PlaceTag都有一个属于同一数据集的标记和位置。我应该使用数据库还是我的应用程序来执行此操作?或者我应该重新构建我的模型,以便更容易地实施此约束

FWIW,这是一个开源项目,我创建这些表的PR在这里:如果有帮助的话,该项目正在使用Django。

在Django中“强制”(注意引号)的一种方法是覆盖
PlaceTag
save()
方法。无论何时
self.place.dataset!=self.tag.dataset
。但是您应该注意到,在某些情况下,Django不会调用模型的自定义
save()
方法:

  • 在查询集上调用
    update()
    方法时。此方法用于批量更新,因此,出于性能原因,直接在数据库级别进行更新
  • 内部(数据)迁移自定义
    save()
    方法不可用

  • 在这两种情况下,我建议的方法对于强制执行约束(因此在开始时使用引号)没有用处。当然,这与在数据库级别强制执行这一点不同,也没有那么强。无论如何,我不认为有一种可移植的方法(即,在任何或大多数SQL数据库引擎中都可用)来强制执行这样的条件,因为检查它将需要在其他表上进行连接,但在这一点上我可能是错的

    简而言之,最佳方法取决于您预期如何使用这些表。例如,如果所有写入都来自调用
    full\u clean()
    (例如表单)的代码,那么将您的签入
    PlaceTag.clean()
    最有意义。这是一个例子。请注意,Django正在Django 2.2中添加内容。@KevinChristopherHenry感谢您的回答。知道在数据库中这样做是不合理的是很有帮助的,我可以使用Django的模型“强制”这样做。但是我期待着使用Django 2.2的CheckConstraint——也许这会给我提供数据库解决方案:)这个答案,以及上面Kevin的答案,帮助我添加了我需要的验证。我覆盖了模型的
    .save
    方法,使其调用
    .full\u clean
    ,我也覆盖了该方法: