如何在Django模型Meta类中正确引用定义的IntegerChoices枚举
解决方案
首先明确两个核心问题:
- 定义Model内部的Meta类时,MyModel类本身还未完成初始化,无法直接引用类内部定义的
States枚举 - 原代码中
Q(state__in=States)的写法本身有误,__in条件需要传入枚举的取值列表,不能直接传入枚举类本身
下面是两种可行的实现方案:
方案1:将IntegerChoices移到Model类外部定义(最推荐)
这种方式最简洁,也不会破坏代码的可维护性,修改后的代码如下:
# 先定义枚举,再定义Model States = models.IntegerChoices('States', 'PROGRESSING INSTALLED DELETED') class MyModel(models.Model): state = models.PositiveSmallIntegerField(choices=States.choices, help_text='Defines the cluster\'s current state') class Meta: constraints = [ # 注意这里要调用.values获取所有枚举值的列表 models.CheckConstraint(check=models.Q(state__in=States.values), name='cluster_state_valid'), ]
如果担心枚举和Model耦合度高,不想暴露在模块顶层,只要保证枚举定义顺序在MyModel之前即可。
方案2:如果必须保留枚举为Model的内部属性
可以先声明枚举变量,再赋值给Model的类属性,代码如下:
# 先在模块内声明枚举变量 _States = models.IntegerChoices('States', 'PROGRESSING INSTALLED DELETED') class MyModel(models.Model): States = _States state = models.PositiveSmallIntegerField(choices=States.choices, help_text='Defines the cluster\'s current state') class Meta: constraints = [ models.CheckConstraint(check=models.Q(state__in=_States.values), name='cluster_state_valid'), ]
这种方式既保留了MyModel.States的调用方式,也解决了Meta类内引用的问题。
额外说明:如果你只需要应用层面的校验不需要数据库层面的Check约束,其实PositiveSmallIntegerField指定choices参数后,Django在调用full_clean()或者表单提交时会自动做合法性校验,不需要额外加约束。只有需要数据库层面强制校验的场景才需要添加上述CheckConstraint。
内容的提问来源于stack exchange,提问作者Will Gordon
相关产品推荐
相关产品推荐

