如何在外部类未完全定义时引用其内部类或属性(Django模型场景)
如何在外部类未完全定义时引用其内部类或属性(Django模型场景)
这个问题我之前也碰到过,确实挺坑的——Python在解析类定义的时候,外部类还没完全创建好,这时候直接用类名去引用内部类肯定会报错。不过不用改结构就能解决,给你几个实用的办法:
方法一:直接引用内部类的名字(最推荐)
因为在定义Meta类的时候,StatusChoices已经在DummyModel的类命名空间里存在了,所以不需要加DummyModel前缀,直接写StatusChoices就行:
class DummyModel(models.Model): class StatusChoices(models.TextChoices): ACTIVE = "active", _("Active") INACTIVE = "inactive", _("Inactive") status = models.CharField( max_length=15, choices=StatusChoices.choices, verbose_name=_("Status"), help_text=_("Current status of the model."), default=StatusChoices.ACTIVE, null=False, blank=False, ) class Meta: verbose_name = _("Dummy Model") verbose_name_plural = _("Dummy Models") constraints = [ models.CheckConstraint( name="%(app_label)s_%(class)s_status_valid", # 这里直接用StatusChoices,不用加DummyModel前缀 check=models.Q(status__in=[choice.value for choice in StatusChoices]), ) ]
Python在解析类体时,会按顺序执行代码,StatusChoices在Meta之前定义,所以Meta类的代码可以直接访问同一个类体里的名字,不用等整个DummyModel类完全创建。这个方法完全符合你不想改变代码结构的要求。
方法二:类定义完成后动态添加约束
如果第一种方法因为某些特殊场景不生效,可以先给Meta的constraints留空,等整个DummyModel类定义完成后再添加约束:
class DummyModel(models.Model): class StatusChoices(models.TextChoices): ACTIVE = "active", _("Active") INACTIVE = "inactive", _("Inactive") status = models.CharField( max_length=15, choices=StatusChoices.choices, verbose_name=_("Status"), help_text=_("Current status of the model."), default=StatusChoices.ACTIVE, null=False, blank=False, ) class Meta: verbose_name = _("Dummy Model") verbose_name_plural = _("Dummy Models") constraints = [] # 先初始化空列表 # 类定义完成后,动态添加约束 DummyModel._meta.constraints.append( models.CheckConstraint( name="%(app_label)s_%(class)s_status_valid", check=models.Q(status__in=[choice.value for choice in DummyModel.StatusChoices]), ) )
这时候DummyModel已经完全创建,引用DummyModel.StatusChoices就不会有问题了,适合需要动态生成约束的复杂场景。
方法三:利用TextChoices的内置属性简化代码
Django 3.2及以上版本的TextChoices提供了values属性,直接返回所有选项值的列表,这样可以省去手动推导的代码,同样用直接引用的方式即可:
constraints = [ models.CheckConstraint( name="%(app_label)s_%(class)s_status_valid", check=models.Q(status__in=StatusChoices.values), ) ]
这种方式更简洁,还能避免重复代码,是锦上添花的小技巧。
备注:内容来源于stack exchange,提问作者Julio
相关产品推荐
相关产品推荐

