15

Is there any best practice in handling "support tables" in Django?

I dislike Field.choices, as it doesn't really enforce integrity (it doesn't even create check constraints), so I prefer creating a full-blown model (and often, I find myself adding additional fields in the support table).

Now, if I use a full model, I suppose the right way to go is to create an initial data fixture for the table content, but is there a "right way" to have named instances of the row, say...

class State(models.Model): name = model.TextField() STATES = dict( NEW=State.objects.get(pk=0), IN_PROGRESS=State.objects.get(pk=1), ) 

... or something like that.

What do you use?

2
  • 3
    I now this is from 11 months ago, but did you find any particular good practice for this? Wondering the same thing here. Commented Feb 18, 2013 at 3:29
  • I was thinking about using an EnumField as recommended below to control the values so that the database values don't have to be looked up dynamically. But then to get the value of the enums being stored in a table, to somehow enforce that with Django's own migrations. Haven't found a clean way to do that yet, but there's another idea on the table. Commented Aug 17, 2021 at 19:49

2 Answers 2

10

Django ORM checks integrity if you specify choices attribute (when you insert/update data via user forms).

You also can set validation logic to database level and use database ENUM field if you db support this.

UPD:

class EnumField(models.Field): def __init__(self, *args, **kwargs): super(EnumField, self).__init__(*args, **kwargs) if not self.choices: raise AttributeError('EnumField requires `choices` attribute.') def db_type(self): return "enum(%s)" % ','.join("'%s'" % k for (k, _) in self.choices) GENDER_MALE = 'm' GENDER_FEMALE = 'f' GENDER_CHOICES = ( (GENDER_MALE, 'Male'), (GENDER_FEMALE, 'Female'), ) class Person(models.Model): name = models.CharField(max_length=50) gender = EnumField(choices=GENDER_CHOICES) 
Sign up to request clarification or add additional context in comments.

2 Comments

I want the constraints to be in the database, and the "enums" to be full models with their own tables. Basically, I'm wondering about the Pythonic/Djangoish way to create the "Python" enum.
I suggest Other/Unspecified, too!
3

I have also a use case for database-backed Enum models. I came up with a solution that uses Python descriptors to implement django choices-like interface to the enum values:

from django.db import models class ModelInstance: """Descriptor that uses predefined value fields to access model instances.""" def __init__(self, **kwargs): self._instance_attributes = kwargs self._instance = None def __get__(self, instance, instance_type): if not self._instance: self._instance = instance_type.objects.get(**self._instance_attributes) return self._instance class EnumModel(models.Model): name = models.CharField(max_length=100) JOHN = ModelInstance(name='John') FRED = ModelInstance(name='Fred') 

JOHN and FRED are lazily evaluated model instances obtained for specific query params (name=value). I assume that the queries evaluate to unique rows in the table.

To use it, you first need to add rows to the database for John and Fred:

In [1]: EnumModel.objects.create(name="Fred") In [2]: EnumModel.objects.create(name="John") 

Then you can then access the model instances using the class attributes:

In [3]: EnumModel.JOHN Out[3]: <EnumModel: EnumModel object (1)> In [4]: EnumModel.FRED Out[4]: <EnumModel: EnumModel object (2)> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.