I have a model class of which I want two fields to be a choice fields, so to populate those choices I am using an enum as listed below
#models.py
class Trans
According to your reference from https://hackernoon.com/using-enum-as-model-field-choice-in-django-92d8b97aaa63. The choices should be list of tuple, while yours will return a tuple of tuple. More over i is different from i.name. Try:
#enums.py
class TransactionType(Enum):
IN = "IN",
OUT = "OUT"
@classmethod
def choices(cls):
return [(i, i.value) for i in cls]
By the way Djanog also supports the Python 3's auto() as the Enum value. You can use the following helperclass to make your life easier.
from django.db.models.enums import TextChoices
class AutoEnumChoices(TextChoices):
def _generate_next_value_(name, start, count, last_values): # @NoSelf
return name.lower()
@property
def choices(cls): # @NoSelf
empty = [(None, cls.__empty__)] if hasattr(cls, '__empty__') else []
return empty + [(member.value, member.label) for member in cls]
Then use it in your choices definition:
class TransferBasicStatus(AutoEnumChoices):
NONE = auto()
WAITING = auto()
PENDING = auto()
PROGRESS = auto()
SUCCESS = auto()
DECLINED = auto()
ENDED = 'ended', _('Ended - The transfer has ended with mixed states')
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: str
s = 'my str',
print(type(s))
# output: tuple
class Transaction(models.Model):
trasaction_status = models.CharField(max_length=255, choices=TransactionStatus.choices())
transaction_type = models.CharField(max_length=255, choices=TransactionType.choices())
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)
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.
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:
label
. The label
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..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.For more info, check the documentation