Bagaimana saya pergi tentang menentukan dan menggunakan ENUM dalam model Django?
Bagaimana saya pergi tentang menentukan dan menggunakan ENUM dalam model Django?
Jawaban:
Dari dokumentasi Django :
MAYBECHOICE = (
('y', 'Yes'),
('n', 'No'),
('u', 'Unknown'),
)
Dan Anda menentukan charfield dalam model Anda:
married = models.CharField(max_length=1, choices=MAYBECHOICE)
Anda dapat melakukan hal yang sama dengan bidang integer jika Anda tidak ingin memiliki huruf di db Anda.
Jika demikian, tulis ulang pilihan Anda:
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) )
Menggunakan choices
parameter tidak akan menggunakan tipe ENUM db; itu hanya akan membuat VARCHAR atau INTEGER, tergantung pada apakah Anda menggunakan choices
CharField atau IntegerField. Secara umum, ini baik-baik saja. Jika penting bagi Anda bahwa tipe ENUM digunakan di tingkat database, Anda memiliki tiga opsi:
Dengan salah satu opsi ini, Anda bertanggung jawab untuk menangani implikasi portabilitas lintas database. Pada opsi 2, Anda dapat menggunakan SQL kustom khusus database-backend untuk memastikan ALTER TABLE Anda hanya berjalan di MySQL. Di opsi 3, metode db_type Anda perlu memeriksa mesin database dan menyetel jenis kolom db ke jenis yang sebenarnya ada di database itu.
PEMBARUAN : Sejak kerangka migrasi ditambahkan di Django 1.7, opsi 1 dan 2 di atas seluruhnya sudah usang. Opsi 3 selalu merupakan opsi terbaik. Versi baru dari opsi 1/2 akan melibatkan migrasi ubahsuaian yang kompleks menggunakan SeparateDatabaseAndState
- tetapi sebenarnya Anda menginginkan opsi 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:
Ini adalah cara lain yang bagus dan mudah untuk mengimplementasikan enum meskipun tidak benar-benar menyimpan enum di database.
Namun itu memungkinkan Anda untuk mereferensikan 'label' setiap kali menanyakan atau menentukan default sebagai lawan dari jawaban berperingkat teratas di mana Anda harus menggunakan 'nilai' (yang mungkin berupa angka).
Pengaturan choices
pada lapangan akan memperbolehkan beberapa validasi pada akhir Django, tetapi itu tidak akan mendefinisikan bentuk apapun dari tipe yang disebutkan pada akhir basis data.
Seperti yang disebutkan orang lain, solusinya adalah menentukan db_type
pada bidang khusus.
Jika Anda menggunakan backend SQL (misalnya MySQL), Anda dapat melakukannya seperti ini:
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)
Jalankan syncdb
, dan periksa tabel Anda untuk melihat bahwa tabel ENUM
dibuat dengan benar.
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', ...'
.
Jika Anda benar-benar ingin menggunakan database Anda, tipe ENUM:
Semoga berhasil!
Saat ini ada dua proyek github berdasarkan penambahan ini, meskipun saya belum melihat secara tepat bagaimana penerapannya:
Saya tidak berpikir keduanya menggunakan tipe enum DB, tetapi mereka sedang dalam pengerjaan untuk yang pertama.
Dari dokumentasi :
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,
)
Sekarang, ketahuilah bahwa ini tidak memaksakan pilihan pada level database, ini hanya konstruksi Python. Jika Anda juga ingin menerapkan nilai tersebut di database, Anda dapat menggabungkannya dengan batasan database:
class Student(models.Model):
...
class Meta:
constraints = [
CheckConstraint(
check=Q(year_in_school__in=YearInSchool.values),
name="valid_year_in_school")
]