How to use enums as a choice field in django model
Django 3.0 has built-in support for Enums
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.CharField( max_length=2, choices=YearInSchool.choices, default=YearInSchool.FRESHMAN, )
These work similar to enum from Python’s standard library, but with some modifications:
- Enum member values are a tuple of arguments to use when constructing the concrete data type. Django supports adding an extra string value to the end of this tuple to be used as the human-readable name, or
label
. Thelabel
can be a lazy translatable string. Thus, in most cases, the member value will be a(value, label)
two-tuple. If a tuple is not provided, or the last item is not a (lazy) string, the label is automatically generated from the member name. - A
.label
property is added on values, to return the human-readable name.A number of custom properties are added to the enumeration classes –.choices
,.labels
,.values
, and.names
– to make it easier to access lists of those separate parts of the enumeration. Use.choices
as a suitable value to pass to choices in a field definition. - The use of
enum.unique()
is enforced to ensure that values cannot be defined multiple times. This is unlikely to be expected in choices for a field.
For more info, check the documentation
For Django 2.x and lower:
You define an Enum
by setting the various options as documented here:
class TransactionStatus(Enum): INITIATED = "INITIATED" PENDING = "PENDING" COMPLETED = "COMPLETED" FAILED = "FAILED" ERROR = "ERROR"
Note there are no commas! This allows you later in your code to refer to TransactionStatus.ERROR
or TransactionStatus.PENDING
.
The rest of your code is correct. You get the choices
by creating tuples of option.name
, option.value
.
UPDATE: For Django 3.x and higher, use the built-in types TextChoices
, IntegerChoices
and Choices
as described here. That way you don't have to construct the choices
tuple yourself.
Problem in your code is that INITIATED = "INITIATED",
a comma after INITIATED
option and other options. when we add comma after any string it will become a tuple. See an example below
s = 'my str'print(type(s))# output: strs = 'my str',print(type(s))# output: tuple
models.py
class Transaction(models.Model): trasaction_status = models.CharField(max_length=255, choices=TransactionStatus.choices()) transaction_type = models.CharField(max_length=255, choices=TransactionType.choices())
enums.py
class TransactionType(Enum): IN = "IN" OUT = "OUT" @classmethod def choices(cls): print(tuple((i.name, i.value) for i in cls)) return tuple((i.name, i.value) for i in cls)class TransactionStatus(Enum): INITIATED = "INITIATED" PENDING = "PENDING" COMPLETED = "COMPLETED" FAILED = "FAILED" ERROR = "ERROR" @classmethod def choices(cls): print(tuple((i.name, i.value) for i in cls)) return tuple((i.name, i.value) for i in cls)