Specifying a mySQL ENUM in a Django model
From the Django documentation:
MAYBECHOICE = ( ('y', 'Yes'), ('n', 'No'), ('u', 'Unknown'),)
And you define a charfield in your model :
married = models.CharField(max_length=1, choices=MAYBECHOICE)
You can do the same with integer fields if you don't like to have lettersin your db.
In that case, rewrite your choices:
MAYBECHOICE = ( (0, 'Yes'), (1, 'No'), (2, 'Unknown'),)
from django.db import modelsclass EnumField(models.Field): """ A field class that maps to MySQL's ENUM type. Usage: class Card(models.Model): suit = EnumField(values=('Clubs', 'Diamonds', 'Spades', 'Hearts')) c = Card() c.suit = 'Clubs' c.save() """ def __init__(self, *args, **kwargs): self.values = kwargs.pop('values') kwargs['choices'] = [(v, v) for v in self.values] kwargs['default'] = self.values[0] super(EnumField, self).__init__(*args, **kwargs) def db_type(self): return "enum({0})".format( ','.join("'%s'" % v for v in self.values) )
Using the choices
parameter won't use the ENUM db type; it will just create a VARCHAR or INTEGER, depending on whether you use choices
with a CharField or IntegerField. Generally, this is just fine. If it's important to you that the ENUM type is used at the database level, you have three options:
- Use "./manage.py sql appname" to see the SQL Django generates, manually modify it to use the ENUM type, and run it yourself. If you create the table manually first, "./manage.py syncdb" won't mess with it.
- If you don't want to do this manually every time you generate your DB, put some custom SQL in appname/sql/modelname.sql to perform the appropriate ALTER TABLE command.
- Create a custom field type and define the db_type method appropriately.
With any of these options, it would be your responsibility to deal with the implications for cross-database portability. In option 2, you could use database-backend-specific custom SQL to ensure your ALTER TABLE is only run on MySQL. In option 3, your db_type method would need to check the database engine and set the db column type to a type that actually exists in that database.
UPDATE: Since the migrations framework was added in Django 1.7, options 1 and 2 above are entirely obsolete. Option 3 was always the best option anyway. The new version of options 1/2 would involve a complex custom migration using SeparateDatabaseAndState
-- but really you want option 3.