Opened 5 years ago
Closed 5 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 |
Description
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 { 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_typeis the enumeration type, i.e. amodels.Choicessubclass.field_typeis the underlying ORM field type, e.g.models.CharFieldormodels.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:
- 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') @staticmethod def field(**options): options.setdefault("max_length", 2) return models.Charfield(**options)
- Automatically based on the type and values of the enumeration members:
- For string values: a
CharFieldwithmax_lengththe 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.
DateFieldfor date values. - If the field type cannot be inferred, raise an appropriate exception.
- For string values: a
- a new optional
Duplicate of #24342