Bir Django modelinde bir ENUM belirleme ve kullanma konusuna nasıl gidebilirim?
Bir Django modelinde bir ENUM belirleme ve kullanma konusuna nasıl gidebilirim?
Yanıtlar:
Gönderen Django belgeleri :
MAYBECHOICE = (
('y', 'Yes'),
('n', 'No'),
('u', 'Unknown'),
)
Ve modelinizde bir karakter alanı tanımlarsınız:
married = models.CharField(max_length=1, choices=MAYBECHOICE)
Eğer db'nizde harflerin olmasını istemiyorsanız tamsayı alanları için aynısını yapabilirsiniz.
Bu durumda seçimlerinizi yeniden yazı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) )
Kullanımı choices
ENUM db türünü kullanmaz parametreyi; choices
CharField veya IntegerField ile kullanmanıza bağlı olarak sadece bir VARCHAR veya INTEGER yaratacaktır. Genelde bu gayet iyi. ENUM türünün veritabanı düzeyinde kullanılması sizin için önemliyse, üç seçeneğiniz vardır:
Bu seçeneklerden herhangi biriyle, veritabanları arası taşınabilirliğin çıkarımlarıyla başa çıkmak sizin sorumluluğunuz olacaktır. 2. seçenekte, ALTER TABLE'ınızın yalnızca MySQL üzerinde çalıştığından emin olmak için veritabanına özel özel SQL kullanabilirsiniz. 3. seçenekte, db_type yönteminizin veritabanı motorunu kontrol etmesi ve db sütun türünü o veritabanında gerçekte var olan bir türe ayarlaması gerekir.
GÜNCELLEME : Taşıma çerçevesi Django 1.7'de eklendiğinden, yukarıdaki 1 ve 2 numaralı seçenekler tamamen geçersizdir. 3. Seçenek zaten her zaman en iyi seçenekti. Seçenek 1 / 2'nin yeni sürümü, karmaşık bir özel geçişi içerecektir SeparateDatabaseAndState
- ancak gerçekten 3. seçeneği istiyorsunuz.
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:
Bu, numaralandırmaları gerçekten veritabanına kaydetmese de, numaralandırmanın başka bir güzel ve kolay yoludur.
Bununla birlikte, 'değeri' (bir sayı olabilir) kullanmanız gereken en yüksek puanlı yanıtın aksine, varsayılanları sorguladığınızda veya belirtirken 'etikete' başvurmanıza izin verir.
Ayar choices
sahada Django ucunda bazı doğrulama sağlayacak, ancak olmayacak veritabanı ucunda bir sabit tür herhangi bir biçimde tanımlar.
Diğerlerinin de belirttiği gibi çözüm, db_type
özel bir alan üzerinde belirtmektir .
Bir SQL arka ucu kullanıyorsanız (örneğin MySQL), bunu şu şekilde yapabilirsiniz:
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)
Çalıştırın syncdb
ve tablonuzun ENUM
doğru şekilde oluşturulup oluşturulmadığını kontrol edin .
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', ...'
.
Veritabanlarınızı gerçekten kullanmak istiyorsanız ENUM yazın:
İyi şanslar!
Şu anda bunları eklemeye dayanan iki github projesi var, ancak tam olarak nasıl uygulandıklarına bakmadım:
Ben de DB numaralandırma türlerini kullanmayı düşünmüyorum, ancak ilk biri için çalışıyorlar .
Gönderen belgeler :
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,
)
Şimdi, bir veritabanı düzeyinde seçimleri zorlamadığını unutmayın, bu yalnızca Python yapısıdır. Veritabanında bu değeri de uygulamak istiyorsanız, bunu veritabanı kısıtlamalarıyla birleştirebilirsiniz:
class Student(models.Model):
...
class Meta:
constraints = [
CheckConstraint(
check=Q(year_in_school__in=YearInSchool.values),
name="valid_year_in_school")
]