ฉันจะระบุและใช้ ENUM ในโมเดล Django ได้อย่างไร
ฉันจะระบุและใช้ ENUM ในโมเดล Django ได้อย่างไร
คำตอบ:
จากเอกสาร Django :
MAYBECHOICE = (
('y', 'Yes'),
('n', 'No'),
('u', 'Unknown'),
)
และคุณกำหนดชาร์ฟิลด์ในโมเดลของคุณ:
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 ในระดับฐานข้อมูลคุณมีสามตัวเลือก:
ด้วยตัวเลือกใด ๆ เหล่านี้คุณจะต้องรับผิดชอบในการจัดการกับผลกระทบของการพกพาข้ามฐานข้อมูล ในตัวเลือกที่ 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:
นี่เป็นอีกวิธีที่ดีและง่ายในการใช้ enums แม้ว่าจะไม่ได้บันทึก enums ในฐานข้อมูลจริงๆ
อย่างไรก็ตามจะอนุญาตให้คุณอ้างอิง 'ป้ายกำกับ' เมื่อใดก็ตามที่สอบถามหรือระบุค่าเริ่มต้นซึ่งตรงข้ามกับคำตอบที่ได้รับคะแนนสูงสุดซึ่งคุณต้องใช้ 'ค่า' (ซึ่งอาจเป็นตัวเลข)
การตั้งค่า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 | |
+--------+-----------------------------+------+-----+---------+----------------+
'type "enum" does not exist LINE 1: ....tablename" ADD COLUMN "select_user" ENUM('B', ...'
ทำงานสิ้นสุดขึ้นกับข้อผิดพลาด
หากคุณต้องการใช้ฐานข้อมูลของคุณประเภท ENUM:
โชคดี!
ขณะนี้มีโปรเจ็กต์ github สองโปรเจ็กต์จากการเพิ่มสิ่งเหล่านี้แม้ว่าฉันจะไม่ได้ตรวจสอบวิธีการนำไปใช้อย่างชัดเจน
ฉันไม่คิดว่าจะใช้ DB enum types แต่อยู่ในผลงานสำหรับคนแรก
จากเอกสารประกอบ :
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,
)
ตอนนี้โปรดทราบว่ามันไม่ได้บังคับใช้ตัวเลือกในระดับฐานข้อมูลนี่คือการสร้าง Python เท่านั้น หากคุณต้องการบังคับใช้ค่าเหล่านั้นกับฐานข้อมูลคุณสามารถรวมเข้ากับข้อ จำกัด ของฐานข้อมูล:
class Student(models.Model):
...
class Meta:
constraints = [
CheckConstraint(
check=Q(year_in_school__in=YearInSchool.values),
name="valid_year_in_school")
]
ด้านบนของไฟล์ models.py ของคุณเพิ่มบรรทัดนี้หลังจากที่คุณนำเข้า:
enum = lambda *l: [(s,_(s)) for s in l]