How do I go about specifying and using an ENUM in a Django model?
How do I go about specifying and using an 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 letters in your db.
In that case, rewrite your choices:
MAYBECHOICE = (
(0, 'Yes'),
(1, 'No'),
(2, 'Unknown'),
)
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:
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.
If you really want to use your databases ENUM type:
Good luck!
From the documentation:
from django.utils.translation import gettext_lazy as _
class Student(models.Model):
class YearInSchool(models.TextChoices):
FRESHMAN = 'FR', _('Freshman')
SOPHOMORE = 'SO', _('Sophomore')
JUNIOR = 'JR', _('Junior')
SENIOR = 'SR', _('Senior')
GRADUATE = 'GR', _('Graduate')
year_in_school = models.CharField(
max_length=2,
choices=YearInSchool.choices,
default=YearInSchool.FRESHMAN,
)
Now, be aware that it does not enforce the choices at a database level this is Python only construct. If you want to also enforce those value at the database you could combine that with database constraints:
class Student(models.Model):
...
class Meta:
constraints = [
CheckConstraint(
check=Q(year_in_school__in=YearInSchool.values),
name="valid_year_in_school")
]
If you have to have enum type in MySQL table and not a "fake" enum (only visible on python side) then you can try Django-MySQL extension and its EnumField.
The models:
from django.db import models
from django_mysql.models import EnumField
class IceCreamFlavor(models.TextChoices):
CHOCOLATE = "chocolate"
VANILLA = "vanilla"
class IceCream(models.Model):
price = models.DecimalField(max_digits=4, decimal_places=2)
ice_cream_flavor = EnumField(choices=IceCreamFlavor.choices)
Resulting table:
mysql> SHOW COLUMNS IN myapp.db_icecream;
+------------------+-----------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------------+-----------------------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| price | decimal(4,2) | NO | | NULL | |
| ice_cream_flavor | enum('chocolate','vanilla') | NO | | NULL | |
+------------------+-----------------------------+------+-----+---------+----------------+