根据另一个字段的值对 Django 模型添加约束

onl*_*tom 8 python database django django-models

我有一个简单的模型,有 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")
Run Code Online (Sandbox Code Playgroud)

我想添加一个约束,使其passingscore永远不应大于maxscore数据库中的值。

我使用了跨越多个字段的约束unique_together,例如StackOverflow 上的这个线程。但显然这是一个不同的用例。

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

ALTER TABLE tableB ADD CONSTRAINT score_policy_1 CHECK (maxscore >= passingscore) 
Run Code Online (Sandbox Code Playgroud)

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

如果这可能的话,请向我指出在 Django 中编写此约束的更惯用的方法。

Vla*_*kov 10

这应该适用于你的情况。

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")),
            )
        ]
Run Code Online (Sandbox Code Playgroud)