【问题标题】:Adding constraint on Django Models based on values of another field根据另一个字段的值对 Django 模型添加约束
【发布时间】:2019-11-08 04:01:10
【问题描述】:

我有一个带有 1 个主键和 3 个字段的简单模型(简化):

  • 及格分数
  • 最高分
  • 最大尝试次数

此模型是通过继承 django.db.models 创建的。这是最小的可重现代码:

from django.db import models
class QuestionSet(models.Model):
    passingscore = models.PositiveSmallIntegerField("passing score")
    maxscore = models.PositiveSmallIntegerField("max score")
    maxattempt = models.PositiveSmallIntegerField("max attempt")

我想添加一个约束,使passingscore 在数据库中永远不会大于maxscore

根据this thread on StackOverflow,我使用了跨越多个字段的约束,例如unique_together。但显然这是一个不同的用例。

我也简单考虑过直接写PostgreSQL代码加约束:

ALTER TABLE tableB ADD CONSTRAINT score_policy_1 CHECK (maxscore >= passingscore) 

但这违背了使用 ORM 的目的,违反了“松散耦合”的理念,使得在不同的数据库后端之间迁移变得困难。

如果这是可能的,请指出在 Django 中编写此约束的更惯用的方式。

【问题讨论】:

标签: python django database django-models


【解决方案1】:

这应该适用于您的情况。

from django.db import models
class QuestionSet(models.Model):
    passingscore = models.PositiveSmallIntegerField("passing score")
    maxscore = models.PositiveSmallIntegerField("max score")
    maxattempt = models.PositiveSmallIntegerField("max attempt")
    
    class Meta:
        constraints = [
            models.CheckConstraint(
                name="%(app_label)s_%(class)s_passingscore_lte_maxscore",
                check=models.Q(passingscore__lte=models.F("maxscore")),
            )
        ]

【讨论】:

  • 看起来很有希望 - 我会试试这个(一年前已经 > 所以已经离开这个项目了),当我确认它有效时,我会回来并将其标记为已接受回答。非常感谢!
【解决方案2】:

您可以在视图层或数据库层中执行此操作。

如果你想在DB层做,你可以覆盖模型的save方法,并检查那里的值:

def save(self, *args, **kwargs):

    if self.passingscore > self.maxscore:
        raise ValueError("passingscore can't be greater than maxscore")

    super().save(*args, **kwargs)

如果你想处理数据库约束,你可以通过继承BaseConstraint创建你自己的约束类,并将你的sql放在constraint_sql方法中。

【讨论】:

  • 这是一个有用的建议(因此被赞成),但有些更新甚至不会调用 save() 在将值持久化到数据库时。我希望在 db 层上强制执行约束,并且正在考虑是否有办法覆盖 meta 这样做。如果这不是一个选项,那么我会采用您上面建议的内容,即视图/模型中的逻辑,而不是数据库级别的强制执行。
  • @onlyphantom 您可以通过继承BaseConstraint 来创建自己的约束类,并将您的sql 放入constraint_sql 方法中。
猜你喜欢
  • 2011-08-25
  • 2017-02-28
  • 2019-11-01
  • 1970-01-01
  • 2019-02-15
  • 2020-02-26
  • 2020-08-08
  • 1970-01-01
  • 2019-01-01
相关资源
最近更新 更多