I have a scenario where a class contains an inner class, and I want to reference that inner class (or its attributes) within the outer class. Here’s a concrete example using Django:
from django.db import models
from django.utils.translation import gettext_lazy as _
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",
check=models.Q(status__in=[choice.value for choice in DummyModel.StatusChoices]),
)
]
In this case, the constraints list in the Meta class tries to reference DummyModel.StatusChoices
. However, at the time this reference is evaluated, DummyModel
is not fully defined, leading to an error (neither StatusChoices
is accessible in that line).
I would like to solve this without significantly altering the structure of the code—StatusChoices
must remain defined inside DummyModel.
How can I resolve this issue while keeping the inner class and its attributes accessible as intended?
You can probably do this by defining the choices outside the class first, because the Meta
class is actually constructed even before the status
is accessible:
# 🖟 outside DummyModel
class StatusChoices(models.TextChoices):
ACTIVE = 'active', _('Active')
INACTIVE = 'inactive', _('Inactive')
class DummyModel(models.Model):
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',
check=models.Q(
status__in=[choice.value for choice in StatusChoices]
),
)
]
DummyModel.StatusChoices = StatusChoices
For what it is worth, I made a small Django package named django-enforced-choices
[GitHub] that can enforce choices at the database by just looking at the field with choices.