pythondjangopython-3.xdjango-modelsenums

How can one use enums as a choice field in a Django model?


I have a model class in which I want two fields to be choice fields, so to populate those choices I am using an enum as listed below:

#models.py
class Transaction(models.Model):
    transaction_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)

However, when I am trying to access this model through the Django Admin I am getting the following error:

Django Version: 1.11
Exception Type: ValueError
Exception Value:    
too many values to unpack (expected 2)

I followed two articles that described how to use enums:


Solution

  • django > 3.0 - have built-in support for Enums

    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,
        )
    
        def is_upperclass(self):
            return self.year_in_school in {
                self.YearInSchool.JUNIOR,
                self.YearInSchool.SENIOR,
            }
    

    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
    

    #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.value, i.name) for i in cls))
            return tuple((i.value, i.name) for i in cls)
    

    For django > 3.0 https://docs.djangoproject.com/en/4.0/ref/models/fields/#field-choices-enum-types