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[:2] == '__')] # format into django choice tuple choices = tuple([(str(p.value), p) 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.