Opened 4 years ago

Closed 4 years ago

#31861 closed New feature (duplicate)

Model field for enumeration types

Reported by: George Sakkis Owned by: nobody
Component: Database layer (models, ORM) Version: 3.1
Severity: Normal Keywords: enumeration
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


The new enumeration types in Django 3.0 are a great addition and improvement over the previous choices. On the ORM layer however, only the enumeration values are represented, not the enumeration members. I'd like to suggest a new EnumField custom field that refers to the actual enumeration member, similar to how ForeignKey fields refers to the related model object instead of its primary key (or the to_field in general). Proposed usage for the Student example:

from django.utils.translation import gettext_lazy as _

class Student(models.Model):

    class YearInSchool(models.TextChoices):
        FRESHMAN = 'FR', _('Freshman')
        SOPHOMORE = 'SO', _('Sophomore')
        JUNIOR = 'JR', _('Junior')
        SENIOR = 'SR', _('Senior')
        GRADUATE = 'GR', _('Graduate')

    year_in_school = models.EnumField(YearInSchool, default=YearInSchool.FRESHMAN)

    def is_upperclass(self):
        return self.year_in_school in {

In this case, Student.year_in_school would be a YearInSchool member, not a two-letter string.

The proposed signature is the following: class EnumField(enum_type, field_type=None, **options)

  • enum_type is the enumeration type, i.e. a models.Choices subclass.
  • field_type is the underlying ORM field type, e.g. models.CharField or models.PositiveSmallIntegerField.
    • In the simplest implementation, this is a required parameter to be provided by the caller.
    • Alternatively, it could be made optional and inferred based on either of the following:
      1. a new optional field(**options) staticmethod on the enumeration type, if present. For example:
        class YearInSchool(models.TextChoices):
            FRESHMAN = 'FR', _('Freshman')
            SOPHOMORE = 'SO', _('Sophomore')
            JUNIOR = 'JR', _('Junior')
            SENIOR = 'SR', _('Senior')
            GRADUATE = 'GR', _('Graduate')
            def field(**options):
                options.setdefault("max_length", 2)
                return models.Charfield(**options)
      2. Automatically based on the type and values of the enumeration members:
        • For string values: a CharField with max_length the maximum length of the enumeration values.
        • For integer values: one of {PositiveSmallIntegerField, SmallIntegerField, PositiveIntegerField, IntegerField, BigIntegerField}, the smallest that can represent all the enumeration values.
        • And so on for other types where there is a natural python type <=> ORM field mapping, e.g. DateField for date values.
        • If the field type cannot be inferred, raise an appropriate exception.

Change History (1)

comment:1 by Carlton Gibson, 4 years ago

Resolution: duplicate
Status: newclosed

Duplicate of #24342

Note: See TracTickets for help on using tickets.
Back to Top