<p>How do I go about specifying and using an ENUM in a Django model?</p>

[{'answer_id': 21468, 'author': 'fulmicoton', 'author_id': 446497, 'author_profile': 'https://Stackoverflow.com/users/446497', 'pm_score': 7, 'selected': False, 'text': '<p>From the <a href="https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.Field.choices" rel="noreferrer">Django documentation</a>:</p>\n\n<pre><code>MAYBECHOICE = (\n    (\'y\', \'Yes\'),\n    (\'n\', \'No\'),\n    (\'u\', \'Unknown\'),\n)\n</code></pre>\n\n<p>And you define a charfield in your model :</p>\n\n<pre><code>married = models.CharField(max_length=1, choices=MAYBECHOICE)\n</code></pre>\n\n<p>You can do the same with integer fields if you don\'t like to have letters\nin your db.</p>\n\n<p>In that case, rewrite your choices:</p>\n\n<pre><code>MAYBECHOICE = (\n    (0, \'Yes\'),\n    (1, \'No\'),\n    (2, \'Unknown\'),\n)\n</code></pre>\n'}, {'answer_id': 33932, 'author': 'Carl Meyer', 'author_id': 3207, 'author_profile': 'https://Stackoverflow.com/users/3207', 'pm_score': 5, 'selected': False, 'text': '<p>Using the <code>choices</code> parameter won\'t use the ENUM db type; it will just create a VARCHAR or INTEGER, depending on whether you use <code>choices</code> 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:</p>\n\n<ol>\n<li>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.</li>\n<li>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.</li>\n<li>Create a <a href="http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields" rel="noreferrer">custom field type</a> and define the db_type method appropriately.</li>\n</ol>\n\n<p>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 <a href="http://www.djangoproject.com/documentation/model-api/#database-backend-specific-sql-data" rel="noreferrer">database-backend-specific custom SQL</a> 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.</p>\n\n<p><strong>UPDATE</strong>: 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 <code>SeparateDatabaseAndState</code> -- but really you want option 3.</p>\n'}, {'answer_id': 334932, 'author': 'Charles Merriam', 'author_id': 1320510, 'author_profile': 'https://Stackoverflow.com/users/1320510', 'pm_score': 3, 'selected': False, 'text': '<p>If you really want to use your databases ENUM type:</p>\n\n<ol>\n<li>Use Django 1.x</li>\n<li>Recognize your application will only work on some databases.</li>\n<li>Puzzle through this documentation page:<a href="http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields" rel="noreferrer">http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields</a></li>\n</ol>\n\n<p>Good luck!</p>\n'}, {'answer_id': 1530858, 'author': 'Community', 'author_id': -1, 'author_profile': 'https://Stackoverflow.com/users/-1', 'pm_score': 5, 'selected': False, 'text': '<pre><code>from django.db import models\n\nclass EnumField(models.Field):\n    """\n    A field class that maps to MySQL\'s ENUM type.\n\n    Usage:\n\n    class Card(models.Model):\n        suit = EnumField(values=(\'Clubs\', \'Diamonds\', \'Spades\', \'Hearts\'))\n\n    c = Card()\n    c.suit = \'Clubs\'\n    c.save()\n    """\n    def __init__(self, *args, **kwargs):\n        self.values = kwargs.pop(\'values\')\n        kwargs[\'choices\'] = [(v, v) for v in self.values]\n        kwargs[\'default\'] = self.values[0]\n        super(EnumField, self).__init__(*args, **kwargs)\n\n    def db_type(self):\n        return "enum({0})".format( \',\'.join("\'%s\'" % v for v in self.values) )\n</code></pre>\n'}, {'answer_id': 13089465, 'author': 'keithxm23', 'author_id': 1415352, 'author_profile': 'https://Stackoverflow.com/users/1415352', 'pm_score': 3, 'selected': False, 'text': '<p><a href="http://www.b-list.org/weblog/2007/nov/02/handle-choices-right-way/">http://www.b-list.org/weblog/2007/nov/02/handle-choices-right-way/</a></p>\n\n<blockquote>\n<pre><code>class Entry(models.Model):\n    LIVE_STATUS = 1\n    DRAFT_STATUS = 2\n    HIDDEN_STATUS = 3\n    STATUS_CHOICES = (\n        (LIVE_STATUS, \'Live\'),\n        (DRAFT_STATUS, \'Draft\'),\n        (HIDDEN_STATUS, \'Hidden\'),\n    )\n    # ...some other fields here...\n    status = models.IntegerField(choices=STATUS_CHOICES, default=LIVE_STATUS)\n\nlive_entries = Entry.objects.filter(status=Entry.LIVE_STATUS)\ndraft_entries = Entry.objects.filter(status=Entry.DRAFT_STATUS)\n\nif entry_object.status == Entry.LIVE_STATUS:\n</code></pre>\n</blockquote>\n\n<p>This is another nice and easy way of implementing enums although it doesn\'t really save enums in the database.</p>\n\n<p>However it does allow you to reference the \'label\' whenever querying or specifying defaults as opposed to the top-rated answer where you have to use the \'value\' (which may be a number).</p>\n'}, {'answer_id': 19040441, 'author': 'David Cain', 'author_id': 815632, 'author_profile': 'https://Stackoverflow.com/users/815632', 'pm_score': 3, 'selected': False, 'text': '<p>Setting <code>choices</code> on the field will allow some validation on the Django end, but it <em>won\'t</em> define any form of an enumerated type on the database end.</p>\n\n<p>As others have mentioned, the solution is to specify <a href="https://docs.djangoproject.com/en/dev/howto/custom-model-fields/#django.db.models.Field.db_type"><code>db_type</code></a> on a custom field.</p>\n\n<p>If you\'re using a SQL backend (e.g. MySQL), you can do this like so:</p>\n\n<pre class="lang-py prettyprint-override"><code>from django.db import models\n\n\nclass EnumField(models.Field):\n    def __init__(self, *args, **kwargs):\n        super(EnumField, self).__init__(*args, **kwargs)\n        assert self.choices, "Need choices for enumeration"\n\n    def db_type(self, connection):\n        if not all(isinstance(col, basestring) for col, _ in self.choices):\n            raise ValueError("MySQL ENUM values should be strings")\n        return "ENUM({})".format(\',\'.join("\'{}\'".format(col) \n                                          for col, _ in self.choices))\n\n\nclass IceCreamFlavor(EnumField, models.CharField):\n    def __init__(self, *args, **kwargs):\n        flavors = [(\'chocolate\', \'Chocolate\'),\n                   (\'vanilla\', \'Vanilla\'),\n                  ]\n        super(IceCreamFlavor, self).__init__(*args, choices=flavors, **kwargs)\n\n\nclass IceCream(models.Model):\n    price = models.DecimalField(max_digits=4, decimal_places=2)\n    flavor = IceCreamFlavor(max_length=20)\n</code></pre>\n\n<p>Run <code>syncdb</code>, and inspect your table to see that the <code>ENUM</code> was created properly.</p>\n\n<pre class="lang-sql prettyprint-override"><code>mysql&gt; SHOW COLUMNS IN icecream;\n+--------+-----------------------------+------+-----+---------+----------------+\n| Field  | Type                        | Null | Key | Default | Extra          |\n+--------+-----------------------------+------+-----+---------+----------------+\n| id     | int(11)                     | NO   | PRI | NULL    | auto_increment |\n| price  | decimal(4,2)                | NO   |     | NULL    |                |\n| flavor | enum(\'chocolate\',\'vanilla\') | NO   |     | NULL    |                |\n+--------+-----------------------------+------+-----+---------+----------------+\n</code></pre>\n'}, {'answer_id': 22155357, 'author': 'Kenzo', 'author_id': 1576113, 'author_profile': 'https://Stackoverflow.com/users/1576113', 'pm_score': -1, 'selected': False, 'text': '<p>A the top of your models.py file, add this line after you do your imports:</p>\n\n<pre><code>    enum = lambda *l: [(s,_(s)) for s in l]\n</code></pre>\n'}, {'answer_id': 28408589, 'author': 'AncientSwordRage', 'author_id': 1075247, 'author_profile': 'https://Stackoverflow.com/users/1075247', 'pm_score': 2, 'selected': False, 'text': '<p>There\'re currently two github projects based on adding these, though I\'ve not looked into exactly how they\'re implemented:</p>\n\n<ol>\n<li><a href="https://github.com/5monkeys/django-enumfield" rel="nofollow">Django-EnumField</a>:<br>\nProvides an enumeration Django model field (using IntegerField) with reusable enums and transition validation. </li>\n<li><a href="https://github.com/hzdg/django-enumfields" rel="nofollow">Django-EnumFields</a>:<br>\nThis package lets you use real Python (PEP435-style) enums with Django.</li>\n</ol>\n\n<p>I don\'t think either use DB enum types, but they are <a href="https://github.com/5monkeys/django-enumfield/issues/18" rel="nofollow">in the works</a> for first one.</p>\n'}, {'answer_id': 58052062, 'author': 'Cesar Canassa', 'author_id': 360829, 'author_profile': 'https://Stackoverflow.com/users/360829', 'pm_score': 3, 'selected': False, 'text': '<h1>Django 3.0 has built-in support for Enums</h1>\n\n<p>From the <a href="https://docs.djangoproject.com/en/dev/ref/models/fields/#field-choices-enum-types" rel="noreferrer">documentation</a>:</p>\n\n<pre class="lang-py prettyprint-override"><code>from django.utils.translation import gettext_lazy as _\n\nclass Student(models.Model):\n\n    class YearInSchool(models.TextChoices):\n        FRESHMAN = \'FR\', _(\'Freshman\')\n        SOPHOMORE = \'SO\', _(\'Sophomore\')\n        JUNIOR = \'JR\', _(\'Junior\')\n        SENIOR = \'SR\', _(\'Senior\')\n        GRADUATE = \'GR\', _(\'Graduate\')\n\n    year_in_school = models.CharField(\n        max_length=2,\n        choices=YearInSchool.choices,\n        default=YearInSchool.FRESHMAN,\n    )\n</code></pre>\n\n<p>Now, be aware that <strong>it does not enforce the choices at a database level</strong> this is Python only construct. If you want to also enforce those value at the database you could combine that with database constraints:</p>\n\n<pre class="lang-py prettyprint-override"><code>class Student(models.Model):\n    ...\n\n    class Meta:\n        constraints = [\n            CheckConstraint(\n                check=Q(year_in_school__in=YearInSchool.values),\n                name="valid_year_in_school")\n        ]\n</code></pre>\n'}, {'answer_id': 73765582, 'author': 'Nikolay', 'author_id': 11620296, 'author_profile': 'https://Stackoverflow.com/users/11620296', 'pm_score': 1, 'selected': False, 'text': '<p>If you have to have enum type in MySQL table and not a &quot;fake&quot; enum (only visible on python side) then you can try <a href="https://github.com/adamchainz/django-mysql" rel="nofollow noreferrer"><strong>Django-MySQL</strong></a> extension and its <a href="https://django-mysql.readthedocs.io/en/latest/model_fields/enum_field.html" rel="nofollow noreferrer">EnumField</a>.</p>\n<p>The models:</p>\n<pre class="lang-py prettyprint-override"><code>from django.db import models\nfrom django_mysql.models import EnumField\n\n\nclass IceCreamFlavor(models.TextChoices):\n    CHOCOLATE = &quot;chocolate&quot;\n    VANILLA = &quot;vanilla&quot;\n\n\nclass IceCream(models.Model):\n    price = models.DecimalField(max_digits=4, decimal_places=2)\n    ice_cream_flavor = EnumField(choices=IceCreamFlavor.choices)\n\n</code></pre>\n<p>Resulting table:</p>\n<pre><code>mysql&gt; SHOW COLUMNS IN myapp.db_icecream;\n+------------------+-----------------------------+------+-----+---------+----------------+\n| Field            | Type                        | Null | Key | Default | Extra          |\n+------------------+-----------------------------+------+-----+---------+----------------+\n| id               | int                         | NO   | PRI | NULL    | auto_increment |\n| price            | decimal(4,2)                | NO   |     | NULL    |                |\n| ice_cream_flavor | enum(\'chocolate\',\'vanilla\') | NO   |     | NULL    |                |\n+------------------+-----------------------------+------+-----+---------+----------------+\n\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/21454', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/2019/']