在Django模型中指定mySQL ENUM

时间:2008-08-21 23:48:09

标签: python mysql django django-models enums

如何在Django模型中指定和使用ENUM?

9 个答案:

答案 0 :(得分:103)

来自Django documentation

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

您在模型中定义了一个字段:

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

如果您不喜欢字母,可以对整数字段执行相同的操作 在您的数据库中。

在这种情况下,请重写您的选择:

MAYBECHOICE = (
    (0, 'Yes'),
    (1, 'No'),
    (2, 'Unknown'),
)

答案 1 :(得分:36)

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

答案 2 :(得分:32)

使用choices参数将不使用ENUM db类型;它只会创建一个VARCHAR或INTEGER,具体取决于您是否将choices与CharField或IntegerField一起使用。一般来说,这很好。如果在数据库级别使用ENUM类型对您很重要,则有三个选项:

  1. 使用“./manage.py sql appname”查看SQL Django生成的SQL,手动修改它以使用ENUM类型,并自行运行。如果您先手动创建表,“。/ manage.py syncdb”将不会弄乱它。
  2. 如果您不想在每次生成数据库时手动执行此操作,请在appname / sql / modelname.sql中放置一些自定义SQL以执行相应的ALTER TABLE命令。
  3. 创建custom field type并相应地定义db_type方法。
  4. 使用这些选项中的任何一个,您都有责任处理跨数据库可移植性的影响。在选项2中,您可以使用database-backend-specific custom SQL来确保您的ALTER TABLE仅在MySQL上运行。在选项3中,db_type方法需要检查数据库引擎并将db列类型设置为该数据库中实际存在的类型。

    更新:由于迁移框架是在Django 1.7中添加的,因此上面的选项1和2完全过时了。无论如何,选项3始终是最佳选择。选项1/2的新版本将涉及使用SeparateDatabaseAndState的复杂自定义迁移 - 但实际上您需要选项3。

答案 3 :(得分:9)

http://www.b-list.org/weblog/2007/nov/02/handle-choices-right-way/

class Entry(models.Model):
    LIVE_STATUS = 1
    DRAFT_STATUS = 2
    HIDDEN_STATUS = 3
    STATUS_CHOICES = (
        (LIVE_STATUS, 'Live'),
        (DRAFT_STATUS, 'Draft'),
        (HIDDEN_STATUS, 'Hidden'),
    )
    # ...some other fields here...
    status = models.IntegerField(choices=STATUS_CHOICES, default=LIVE_STATUS)

live_entries = Entry.objects.filter(status=Entry.LIVE_STATUS)
draft_entries = Entry.objects.filter(status=Entry.DRAFT_STATUS)

if entry_object.status == Entry.LIVE_STATUS:

这是另一种实现枚举的简单方法,尽管它并没有真正保存数据库中的枚举。

然而,它确实允许您在查询或指定默认值时引用“标签”,而不是在必须使用“值”(可能是数字)的最高等级答案时。

答案 4 :(得分:9)

在字段上设置choices将允许对Django端进行一些验证,但不会在数据库端定义任何形式的枚举类型。

正如其他人所提到的,解决方案是在自定义字段上指定db_type

如果你正在使用SQL后端(例如MySQL),你可以这样做:

from django.db import models


class EnumField(models.Field):
    def __init__(self, *args, **kwargs):
        super(EnumField, self).__init__(*args, **kwargs)
        assert self.choices, "Need choices for enumeration"

    def db_type(self, connection):
        if not all(isinstance(col, basestring) for col, _ in self.choices):
            raise ValueError("MySQL ENUM values should be strings")
        return "ENUM({})".format(','.join("'{}'".format(col) 
                                          for col, _ in self.choices))


class IceCreamFlavor(EnumField, models.CharField):
    def __init__(self, *args, **kwargs):
        flavors = [('chocolate', 'Chocolate'),
                   ('vanilla', 'Vanilla'),
                  ]
        super(IceCreamFlavor, self).__init__(*args, choices=flavors, **kwargs)


class IceCream(models.Model):
    price = models.DecimalField(max_digits=4, decimal_places=2)
    flavor = IceCreamFlavor(max_length=20)

运行syncdb,检查您的表格,看看ENUM是否已正确创建。

mysql> SHOW COLUMNS IN icecream;
+--------+-----------------------------+------+-----+---------+----------------+
| Field  | Type                        | Null | Key | Default | Extra          |
+--------+-----------------------------+------+-----+---------+----------------+
| id     | int(11)                     | NO   | PRI | NULL    | auto_increment |
| price  | decimal(4,2)                | NO   |     | NULL    |                |
| flavor | enum('chocolate','vanilla') | NO   |     | NULL    |                |
+--------+-----------------------------+------+-----+---------+----------------+

答案 5 :(得分:6)

如果您真的想使用您的数据库ENUM类型:

  1. 使用Django 1.x
  2. 认识到您的应用程序仅适用于某些数据库。
  3. 通过此文档页面进行拼图:http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields
  4. 祝你好运!

答案 6 :(得分:3)

目前有两个基于添加这些项目的github项目,但我还没有详细研究它们是如何实现的:

  1. Django-EnumField
    提供枚举Django模型字段(使用IntegerField),具有可重用的枚举和转换验证。
  2. Django-EnumFields
    这个包允许你使用真正的Python(PEP435风格)枚举与Django。
  3. 我不认为使用数据库枚举类型,但第一个使用in the works

答案 7 :(得分:0)

Django 3.0内置了对枚举的支持

来自documentation

putchar

现在,请注意,它不会在数据库级别强制选择。这是仅Python构造。如果您还想在数据库中强制执行这些值,则可以将其与数据库约束相结合:

#include <stdio.h>    
int main(){
    char ch = getchar();

    while(ch != '\n'){

        ch = getchar();

        switch(ch){
        case 'A':
        case 'E':
        case 'I':
        case 'O':
        case 'U':
        case 'a':
        case 'e':
        case 'i':
        case 'o':
        case 'u':continue;
        default: putchar(ch);
        }
    }
}

答案 8 :(得分:-2)

在models.py文件的顶部,执行导入后添加以下行:

    enum = lambda *l: [(s,_(s)) for s in l]