﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
31861	Model field for enumeration types	George Sakkis	nobody	"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 [https://docs.djangoproject.com/en/3.1/ref/models/fields/#enumeration-types Student example]: 

{{{
#!python
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 {
            self.YearInSchool.JUNIOR,
            self.YearInSchool.SENIOR,
        }
}}}

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:
      {{{
      #!python
      class YearInSchool(models.TextChoices):
          FRESHMAN = 'FR', _('Freshman')
          SOPHOMORE = 'SO', _('Sophomore')
          JUNIOR = 'JR', _('Junior')
          SENIOR = 'SR', _('Senior')
          GRADUATE = 'GR', _('Graduate')
           
          @staticmethod
          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.
"	New feature	closed	Database layer (models, ORM)	3.1	Normal	duplicate	enumeration		Unreviewed	0	0	0	0	0	0
