【问题标题】:Django uniqueness constraint when a specific field is True特定字段为 True 时的 Django 唯一性约束
【发布时间】:2015-11-14 10:42:36
【问题描述】:

我有一个这样的 Django 模型:

class Process(Place):
    isRunning = models.BooleanField(default=True)
    name      = models.CharField(max_length=20)

isRunning 为真时,我想强制name 字段是唯一的。

这种约束在 Django 模型中是否可行?


这可能是this question 的副本,但它没有一个公认的答案,自从被问到 Django 已经发展了很多。

【问题讨论】:

  • 你可以指定unique_together fields,但这也将强制nameisRunningfalse的记录中是唯一的(即你有两组唯一的名字)......否则你可以自定义 model validation 虽然记住它只在保存 ModelForm 和 Django 管理员时自动调用,而不是在执行 instance.save()

标签: django


【解决方案1】:

如果您的数据库支持,您可以设置partial unique index

部分索引是建立在表的子集上的索引;子集由条件表达式(称为部分索引的谓词)定义。索引仅包含满足谓词的那些表行的条目。

在 2.2 版以下,对此没有特殊的 Django 支持,但您可以在数据迁移中进行设置(有关详细信息,请参阅here)。

在你的情况下,它看起来像:

operations = [
    migrations.RunSQL("CREATE UNIQUE INDEX running_name ON app_process(isRunning, name)
                       WHERE isRunning"),
]

从 2.2 版开始,您可以在模型中简单地 declare the partial unique index

from django.db.models import Q, UniqueConstraint

class Process(Place):
    ...
    class Meta:
        constraints = [UniqueConstraint(fields=["name"], condition=Q(isRunning=True))]

【讨论】:

    【解决方案2】:

    唯一字段意味着在数据库中为该字段构建了唯一索引。

    现在,由于您的字段依赖于同一模型中的字段,因此您可以选择在保存模型时对其进行验证。

    您可以覆盖模型 save() 方法,例如:

    def save(self, *args, **kwargs):
        #check if isRunning is true or not    
        super(Model, self).save(*args, **kwargs)
    

    【讨论】:

    • 这很好很简单。我宁愿对 SQL 不闻不问,所以我会走这条路。
    • @ajwood:请注意,如果您依赖覆盖save(),您将受限于使用它的那些方法。特别是,您将无法使用.update().bulk_create()。在数据库中有约束的好处是你知道无论如何它都会被强制执行。
    • 这不应该是接受者的答案,因为它没有在数据库级别强制执行(请参阅下面的投票较高的答案)。一开始覆盖这样的各种方法似乎是个好主意,但在某些时候会受到伤害,所以如果有另一种方法来解决它通常会更好:)
    【解决方案3】:

    您可以添加一个额外的字段,例如stopped_at 来记录进程被杀死的时间。

    并创建一个唯一约束:

    unique_together = ('name', 'stopped_at')
    

    stopped_at 可以设置为 None 或新进程的某个常量值。

    此约束将确保名称在正在运行的进程中是唯一的。并且停止的进程可能具有相同的名称,因为它们的stopped_at 总是不同的(希望或者您可以在这个棘手的字段中添加其他信息以保证停止进程的唯一性)。

    【讨论】:

      猜你喜欢
      • 2023-02-13
      • 2018-05-09
      • 1970-01-01
      • 1970-01-01
      • 2019-09-25
      • 2015-09-19
      • 2011-11-12
      • 2019-09-29
      • 1970-01-01
      相关资源
      最近更新 更多