How can I directly create a `models.TextChoices` from an existing `Enum` class?

Hello Django community!
While refactoring my Django application, I realized that I was referencing several models.TextChoices classes from outside the models.py scope — which didn’t feel quite right.

To improve this, I decided to redefine those choices using enum.StrEnum and then generate corresponding models.TextChoices classes from them.

Here’s a small helper function I wrote for that:

I’d love to hear your thoughts, feedback, or any tips on better patterns for managing Django choice fields with enums.

Thanks in advance!

Hallo!
If i understand you - correctly, This’s (simply variant):

# enums.py
from enum import StrEnum

class UserStatus(StrEnum):
    ACTIVE = "active"
    INACTIVE = "inactive"
    SUSPENDED = "suspended"

class ArticleStatus(StrEnum):
    DRAFT = "draft"
    PUBLISHED = "published"
    ARCHIVED = "archived"

# models.py
from django.db import models
from .enums import UserStatus, ArticleStatus

class User(models.Model):
    status = models.CharField(
        max_length=20,
        choices=TextChoices.from_enum(UserStatus),
        default=UserStatus.ACTIVE.value
    )

class Article(models.Model):
    status = models.CharField(
        max_length=20,
        choices=TextChoices.from_enum(ArticleStatus),
        default=ArticleStatus.DRAFT.value
    )

You might also consider a decorator

def django_choices(enum_cls: Type[Enum]) -> Type[TextChoices]:
    """Decorator to convert an Enum to Django TextChoices."""
    return TextChoices.from_enum(enum_cls)

# Usage:
# @django_choices
# class Status(StrEnum):
#     ACTIVE = "active"
#     INACTIVE = "inactive"

My variant which I aften use, it’s (example) :slight_smile:

# settings.py
from django.utils.translation import gettext_lazy as _
AGE_RATING_CHOICES = [
    ("0+", _("Без возрастных ограничений")),
    ("6+", _("От 6 лет")),
    ("12+", _("От 12 лет")),
    ("16+", _("От 16 лет")),
    ("18+", _("Совершеннолетним")),
]

# views.py
from settings.py import AGE_RATING_CHOICES

class User(models.Model):
    status = models.CharField(
        max_length=20,
        choices=AGE_RATING_CHOICES,
        default=AGE_RATING_CHOICES[0]
    )

@Tryd0g0lik Thanks for the comment!

I looked through the docs you shared, but I couldn’t find where TextChoices.from_enum() is defined.
Does Django actually provide that method?

This page, doesn/t have the [special this method](django/django/db/models/enums.py at main · django/django · GitHub]. I show you the simply methods. They are how alternative for chose. You have a list from alias and descript/


P.S.: and i said that -

If i understand you

1 Like