tags:

views:

3141

answers:

6

The title more or less says it all. How do I go about specifying and using an ENUM in a Django model?

+6  A: 

Here is the answer in django doc: http://www.djangoproject.com/documentation/model-api/

MAYBECHOICE = (
    ('y', 'Yes'),
    ('n', 'No'),
    ('u', 'Unknown'),
)

And you define a charfield in your model :

married = models.CharField(maxlength=1, choices=MAYBECHOICE)

You can do the same with integer fields if you don't like to have letters in your db.

In that case, rewrite you choices:

MAYBECHOICE = (
    (0, 'Yes'),
    (1, 'No'),
    (2, 'Unknown'),
)
poulejapon
+2  A: 

Steve, if you meant using the MySQL ENUM type, then you are out of luck, as far as I know Django doesn't provide support for that (that feature is not available in all DBs supported by Django).

The answer provided by Paul works, but it won't define the type in the DB.

dguaraglia
+7  A: 

davidg is correct that using the choices parameter as Paul suggests 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 for some reason it's important to you that the ENUM type is used at the database level, you have three options:

  1. 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.
  2. 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.
  3. 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 settings.DATABASE_ENGINE and set the db column type to a type that actually exists in that database.

Carl Meyer
+3  A: 

A custom enum field type: http://www.djangosnippets.org/snippets/864/

Have you ever used South with this custom field?
John Giotta
I did, and had to drop that table and syncdb, which worked, but of course you have to this kind of migration manually on production server. For the rest, I'm quite satisfied with this solution. It's closest to Java Enum type.
skrat
+3  A: 

If you really want to use your databases ENUM type:

  1. Use Django 1.x
  2. Recognize your application will only work on some databases.
  3. Puzzle through this documentation page:http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields

Good luck!

Charles Merriam
+2  A: 
from django.db import models

class 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) )
arunbear