如何在Django模型中指定和使用ENUM?
从Django文档:
MAYBECHOICE = ( ('y', 'Yes'), ('n', 'No'), ('u', 'Unknown'), )
然后在模型中定义一个charfield:
married = models.CharField(max_length=1, choices=MAYBECHOICE)
如果您不希望在数据库中包含字母,则可以对整数字段执行相同操作.
在这种情况下,重写您的选择:
MAYBECHOICE = ( (0, 'Yes'), (1, 'No'), (2, 'Unknown'), )
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) )
使用该choices
参数将不使用ENUM db类型; 它只会创建一个VARCHAR或INTEGER,具体取决于您使用choices
的是CharField还是IntegerField.一般来说,这很好.如果在数据库级别使用ENUM类型对您很重要,则有三个选项:
使用"./manage.py sql appname"查看SQL Django生成,手动修改它以使用ENUM类型,并自行运行.如果您先手动创建表,"./ manage.py syncdb"将不会乱用它.
如果您不希望每次生成数据库时手动执行此操作,请在appname/sql/modelname.sql中放置一些自定义SQL以执行相应的ALTER TABLE命令.
创建自定义字段类型并适当地定义db_type方法.
使用这些选项中的任何一个,您都有责任处理跨数据库可移植性的影响.在选项2中,您可以使用特定于数据库后端的自定义SQL来确保您的ALTER TABLE仅在MySQL上运行.在选项3中,db_type方法需要检查数据库引擎并将db列类型设置为该数据库中实际存在的类型.
更新:由于迁移框架是在Django 1.7中添加的,因此上面的选项1和2完全过时了.无论如何,选项3始终是最佳选择.新版本的选项1/2将涉及使用复杂的自定义迁移SeparateDatabaseAndState
- 但实际上您需要选项3.
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:
这是实现枚举,虽然它并没有真正保存枚举数据库中的另一个很好的和简单的方法.
然而,它确实允许您引用"标签"查询或指定的默认值,而不是,你必须使用"值"(它可以是一个数字)的收视率最高的答案每当.
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 | |
+--------+-----------------------------+------+-----+---------+----------------+
如果你真的想使用你的数据库ENUM类型:
使用Django 1.x.
识别您的应用程序仅适用于某些数据库.
通过这个文档页面拼图:http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields
祝好运!