【问题标题】:Constrain Django model by field value按字段值约束 Django 模型
【发布时间】:2019-11-01 15:29:52
【问题描述】:

考虑以下 Django 模型:

class Account(models.Model):

    ACCOUNT_CHOICES = [
        ('m', 'Main',),
        ('s','Secondary'),
        ('o', 'Other')
    ]
    user = models.ForeignKey(User)
    level = models.CharField(max_length=1, choices=ACCOUNT_CHOICES)

如何强制每个用户最多拥有一个“主”帐户的数据库约束,同时仍允许用户拥有任意数量的“辅助”或“其他”帐户?从某种意义上说,我想要unique_together 对应userlevel,但前提是level 的值为m

我知道我可以手动检查是否保存,但我希望数据库自动检查并在适当时提出IntegrityError

【问题讨论】:

  • 我不认为你可以用你当前的模型做到这一点,但如果这些是 level 的唯一选择,请考虑将其更改为可空的 BooleanField,例如 is_main = models.BooleanField(null=True) 并设置将其发送至None 用于辅助帐户。然后 unique_together 将起作用,因为 SQL 将忽略空值。
  • @Selcuk 他们不是唯一的选择,所以我会更新这个问题。但是,如果我按照您的描述添加第三个字段,您的解决方案将起作用
  • 如果您使用的是 postgres,您可以使用部分唯一索引 sqlfiddle.com/#!17/c5441b/1 执行此操作 - 这是一个 sqlfiddle - 如果这是您要查找的内容,请告诉我,我会创建一个答案@ZG101
  • @Trent 感谢您的建议。但是,我宁愿坚持使用 Django ORM 也适用于其他数据库
  • @Trent 恕我直言,您仍然应该将其发布为帮助未来访问者的答案。

标签: django


【解决方案1】:

我认为您无法使用当前模型做到这一点,但如果 level 字段只有这两个选择,请考虑将其更改为可为空的 BooleanField,例如

is_main = models.BooleanField(null=True) 

并将其设置为 None 用于辅助帐户。然后unique_together 将起作用,因为就 SQL 而言,每个空值都是唯一的(请参阅this answer)。

由于level 字段有更多选择,正如您稍后澄清的那样,您可以添加第三个字段并可能覆盖.save() 方法以使其自动设置为None 如果level 不是@987654334 @ 更方便。

编辑:如果您不关心可移植性,@Trent 建议 PostgreSQL 支持部分唯一索引,例如:

create unique index u_i on accounts(user_id, level_id) WHERE level_id = 'm';

这是SQL Fiddle

编辑 2: 实际上,从 Django 2.2 开始,似乎终于可以在 Django ORM 中创建部分索引了。详情请见this question

【讨论】:

  • 在 Django 中找到部分索引的好方法!
猜你喜欢
  • 2011-08-25
  • 1970-01-01
  • 2019-11-08
  • 1970-01-01
  • 2021-08-15
  • 2020-02-26
  • 2019-02-15
  • 2016-05-21
  • 2016-02-19
相关资源
最近更新 更多