我有一个具有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中编写此约束的更惯用的方式。
答案 0 :(得分:2)
这应该适合您的情况。
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")),
)
]
答案 1 :(得分:1)
您可以在视图层或数据库层中进行操作。
如果要在数据库层中执行此操作,则可以覆盖模型的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
方法中。