Enum using Django ModelField choices as string -- anti-pattern?

django, enums, python

Solution

You might want to consider the Django-model-utils `Choices` library, which would give you some more control over the text versions of the enum.

To answer your question, not everything lends itself to an integer identifier. Consider states, Australia has 7 and they have a fixed when known set:

ACT - Australian Capital Territory
NSW - New South Wales
NT  - Northern Territory
QLD - Queensland
SA  - South Australia
TAS - Tasmania
VIC - Victoria
WA  - Western Australia

Since these are relatively fixed (the make up of the country is unlikely to change, there is no reason to assign an integer to each, when the textual coding, with the full name works just as well.

I wouldn't say that using a `CharField` as a choice is an anti-pattern, just an approach that should only be applied if you are certain that the abbreviated versions for the database make sense when stored as text.

Also you can use `Enum` to store your values

from enum import Enum

class Countries(Enum):
   ACT = "Australian Capital Territory"
   NSW = "New South Wales"
   ...

class MyModel(models.Model):
    country = models.CharField(choices=[(tag.name, tag.value) for tag in Countries])

Problem

I have a Django field that I'm using basically as an enum for notification preferences. Right now I have it set up like so: ``` class MyModel(models.Model): # ... EVERY_TIME = 'every'; WEEKLY = 'weekly'; NEVER = 'never' NOTIFICATION_CHOICES = ((EVERY_TIME, "Every time"), (WEEKLY, "Weekly"), (NEVER, "Never")) notification_preferences = models.CharField(choices=NOTIFICATION_CHOICES, default=EVERY_TIME, max_length=10) ``` I know that generally this kind of enum should be set up as a `models.IntegerField` rather than a `CharField`, but since the front-end uses Angular and the data is all served via an API, I feel like it might provide a bit more useful information for the front-end to receive `'weekly'` rather than `2`, for example. Is it considered bad practice to use a `CharField` as an enum? If so, is my use case small enough that it's not a big deal, or is there something I'm missing that I should change it?

Original source