Django Model Choices using Python Enum

Python 3.4 introduced enums types which seem tailor made for use with django model choices. For some reason there seemed no examples to do this, but it’s relatively simple with some tricks (you may call them warts, django needs to enable this better). These have been back ported to prior python versions via the enum34 package (“pip install enum34”).

In this example, we’ll use an IntEnum to associate a variable with an integer value. For django, this means that the database contains integers, though we have a descriptive text for each choice. This is desirable, as we can abstract the name of the variable from the actual value. If you change / refactor the name, the existing values will simply remain the same.

Here’s the model definition:

from enum import IntEnum, unique

def django_enum(cls):
    # decorator needed to enable enums in django templates
    cls.do_not_call_in_templates = True
    return cls


class MyModel(Model):
    # store the choices in the model, so that they are readily 
    # accessible wherever the model is. 
    # unique ensures all variables are unique
    @unique
    @django_enum
    class MyChoices(IntEnum):
        ready = 0
        set = 10
        go = 20
        complete = 100

    # transform enum into choices conform format [(value, str)]
    # also replacing underscore with a space for readability
    status = IntegerField(choices=[(choice.value, choice.name.replace("_", " ")) for choice in MyChoices])

You can now access this in your template as you would expect:

{% if mymodel.status == mymodel.MyChoices.ready %}
    We are ready! {{ mymodel.MyChoices.ready.name }}
{% elif mymodel.status >= mymodel.MyChoices.set %}
    Set, go or complete: {{ mymodel.get_status_display }}
{% endif %}

In python, the enums can be accessed by their value or their name:

# let's display the name
MyModel.MyChoices.ready.name
# let's display the value
MyModel.MyChoices.ready.value

# python will automatically compare the int value when comparing. This returns True
MyModel.MyChoices.ready == 0

# this will return 'MyChoices.ready'
str(MyModel.MyChoices.ready)

That’s all I’ve needed so far. Read up more on the official docs at
https://docs.python.org/3/library/enum.html and let me know if this can be improved in any way!

If you want to know why you need the django_enum decorator, read this:
http://stackoverflow.com/questions/35953132/how-to-access-enum-types-in-django-templates

 
42
Kudos
 
42
Kudos

Now read this

How did Apple forget to focus its product line-up?!

When Steve Jobs returned to Apple he famously trimmed the line-up to only a few products, thereby focussing the company and presenting a coherent set of options to consumers. As Apple has grown over the last couple of years, its product... Continue →