Tag Archives: model-fields

How to use Enums for Django Field.choices

In Django when using the choices parameter on a form field the format passed in must be as follows:

# within your models.Model class...
STUDENT_TYPE_CHOICES = (
    ('0', 'freshman'),
    ('1', 'sophomore'),
    ('2', 'junior'),
    ('3', 'senior'),
)
student_type = models.CharField(max_length=1, choices=STUDENT_TYPE_CHOICES)

This means elsewhere in your code if you want to specify a choice field value, you’d have to enter the first slot of the tuple’s value, e.g.:

junior_students = Student.objects.filter(student_type='2')

This is pretty terrible since it’s hardcoded in our source, possibly over many files.

How to fix this mess:

First, install enum34 on the commandline

pip install enum34

In my project I added common/utils.py containing the following:

import inspect
from enum import Enum

class ChoiceEnum(Enum):

    @classmethod
    def choices(cls):
        # get all members of the class
        members = inspect.getmembers(cls, lambda m: not(inspect.isroutine(m)))
        # filter down to just properties
        props = [m for m in members if not(m[0][:2] == '__')]
        # format into django choice tuple
        choices = tuple([(str(p[1].value), p[0]) for p in props])
        return choices

That’s the hard work over.

Now when you create your choice field:

from common.utils import ChoiceEnum

class StudentTypes(ChoiceEnum):
    freshman = 0
    sophomore = 1
    junior = 2
    senior = 3

# within your models.Model class...
student_type = models.CharField(max_length=1, choices=StudentTypes.choices())

Now if we need to access StudentTypes from elsewhere in our source code, we can simply:

# obviously import StudentTypes
junior_students = Student.objects.filter(student_type=StudentTypes.junior.value)

That’s it. If anyone knows of a nicer way feel free to comment below.