【问题标题】:How to enforce database constraints between two foreign keys on a join table?如何在连接表上的两个外键之间强制执行数据库约束?
【发布时间】:2019-06-12 04:20:40
【问题描述】:

我正在尝试在连接表上的两个外键之间强制执行约束,但我不知道是否可以使用数据库执行此操作,或者是否应该通过我的应用程序或我的 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,如果有帮助的话。

【问题讨论】:

  • 简而言之,最佳方法取决于您预期如何使用这些表格。例如,如果所有写入都来自调用full_clean() 的代码(例如表单),那么将您的检查放入PlaceTag.clean() 是最有意义的。这是related answer。请注意,Django 在 Django 2.2 中添加了declarative syntax for check contraints
  • @KevinChristopherHenry 谢谢你的回答。知道在数据库中执行此操作是不合理的,这很有帮助,我可以使用 Django 的模型“强制”执行此操作。但我期待使用 Django 2.2 的 CheckConstraint - 也许这会给我数据库解决方案:)

标签: django database django-models orm model


【解决方案1】:

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

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

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 2021-07-19
  • 2012-04-04
  • 1970-01-01
  • 2016-03-24
  • 1970-01-01
  • 2013-06-19
相关资源
最近更新 更多