Câu trả lời:
Từ tài liệu Django :
MAYBECHOICE = (
('y', 'Yes'),
('n', 'No'),
('u', 'Unknown'),
)
Và bạn xác định một trường biểu đồ trong mô hình của mình:
married = models.CharField(max_length=1, choices=MAYBECHOICE)
Bạn có thể làm tương tự với các trường số nguyên nếu bạn không muốn có các chữ cái trong db của mình.
Trong trường hợp đó, hãy viết lại các lựa chọn của bạn:
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) )
Việc sử dụng choices
tham số sẽ không sử dụng kiểu ENUM db; nó sẽ chỉ tạo một VARCHAR hoặc INTEGER, tùy thuộc vào việc bạn sử dụng choices
với CharField hay IntegerField. Nói chung, điều này là tốt. Nếu điều quan trọng đối với bạn là loại ENUM được sử dụng ở cấp cơ sở dữ liệu, bạn có ba tùy chọn:
Với bất kỳ tùy chọn nào trong số này, bạn có trách nhiệm phải giải quyết các tác động đối với khả năng di chuyển cơ sở dữ liệu chéo. Trong tùy chọn 2, bạn có thể sử dụng SQL tùy chỉnh dành riêng cho cơ sở dữ liệu phụ trợ phần mềm để đảm bảo ALTER TABLE của bạn chỉ chạy trên MySQL. Trong tùy chọn 3, phương thức db_type của bạn sẽ cần phải kiểm tra công cụ cơ sở dữ liệu và đặt kiểu cột db thành kiểu thực sự tồn tại trong cơ sở dữ liệu đó.
CẬP NHẬT : Vì khung di chuyển đã được thêm vào Django 1.7, các tùy chọn 1 và 2 ở trên đã hoàn toàn lỗi thời. Lựa chọn 3 luôn là lựa chọn tốt nhất. Phiên bản mới của tùy chọn 1/2 sẽ liên quan đến việc di chuyển tùy chỉnh phức tạp bằng cách sử dụng SeparateDatabaseAndState
- nhưng bạn thực sự muốn tùy chọn 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:
Đây là một cách khác hay và dễ thực hiện mặc dù nó không thực sự lưu các enum trong cơ sở dữ liệu.
Tuy nhiên, nó cho phép bạn tham chiếu đến 'nhãn' bất cứ khi nào truy vấn hoặc chỉ định giá trị mặc định trái ngược với câu trả lời được xếp hạng cao nhất, nơi bạn phải sử dụng 'giá trị' (có thể là một số).
Thiết lập choices
trên trường sẽ cho phép một số xác thực trên đầu Django, nhưng nó sẽ không xác định bất kỳ dạng nào của kiểu liệt kê trên đầu cơ sở dữ liệu.
Như những người khác đã đề cập, giải pháp là chỉ định db_type
trên một trường tùy chỉnh.
Nếu bạn đang sử dụng chương trình phụ trợ SQL (ví dụ: MySQL), bạn có thể làm như sau:
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)
Chạy syncdb
và kiểm tra bảng của bạn để xem bảng ENUM
đã được tạo đúng cách chưa.
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 | |
+--------+-----------------------------+------+-----+---------+----------------+
'type "enum" does not exist LINE 1: ....tablename" ADD COLUMN "select_user" ENUM('B', ...'
.
Nếu bạn thực sự muốn sử dụng cơ sở dữ liệu của mình, loại ENUM:
Chúc may mắn!
Hiện tại có hai dự án github dựa trên việc thêm những thứ này, mặc dù tôi chưa xem xét chính xác cách chúng được triển khai:
Tôi không nghĩ sẽ sử dụng các kiểu enum DB, nhưng chúng đang hoạt động cho kiểu đầu tiên.
Từ tài liệu :
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,
)
Bây giờ, hãy lưu ý rằng nó không thực thi các lựa chọn ở cấp cơ sở dữ liệu, đây là cấu trúc chỉ của Python. Nếu bạn cũng muốn thực thi các giá trị đó tại cơ sở dữ liệu, bạn có thể kết hợp giá trị đó với các ràng buộc cơ sở dữ liệu:
class Student(models.Model):
...
class Meta:
constraints = [
CheckConstraint(
check=Q(year_in_school__in=YearInSchool.values),
name="valid_year_in_school")
]