首页 > 解决方案 > 如何在连接表上的两个外键之间强制执行数据库约束?

问题描述

我正在尝试在连接表上的两个外键之间强制执行约束,但我不知道是否可以使用数据库执行此操作,或者是否应该通过我的应用程序或 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 有一个 Tag 和一个 Place 属于同一个 Dataset 的约束。我应该使用数据库还是我的应用程序来执行此操作?或者我应该重新构建我的模型以更轻松地执行此约束?

FWIW,这是一个开源项目,我创建这些表的 PR 在这里:https ://github.com/mapseed/api/pull/161/files如果有帮助,该项目正在使用 Django。

标签: djangodatabasedjango-modelsormmodel

解决方案


在 Django 中“强制”(注意引号)的一种方法是覆盖PlaceTag'save()方法。在那里,您可以随时引发异常self.place.dataset != self.tag.dataset。然而你应该注意到,在某些情况下 Django 不会调用save()模型的自定义方法:

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

在这两种情况下,我提出的方法对强制执行约束没有用(因此开头的引号)。这当然与在数据库级别执行此操作不同,也没有那么强大。无论如何,我认为没有一种可移植的方式(即在任何或大多数 SQL 数据库引擎中都可用)来强制执行这样的条件,因为检查它需要在其他表上进行连接,但我可能在这个问题上错了。


推荐阅读