Як я можу визначитись із використанням ENUM у моделі Django?
Як я можу визначитись із використанням ENUM у моделі Django?
Відповіді:
З документації про Джанго :
MAYBECHOICE = (
('y', 'Yes'),
('n', 'No'),
('u', 'Unknown'),
)
І ви визначаєте в своїй моделі знак поля:
married = models.CharField(max_length=1, choices=MAYBECHOICE)
Ви можете зробити те ж саме з цілими полями, якщо вам не подобається мати літери у db.
У такому випадку перепишіть свій вибір:
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:
Це ще один приємний та простий спосіб впровадження перерахунків, хоча він не дійсно зберігає переліків у базі даних.
Однак це дозволяє вам посилатися на "мітку", коли ви запитуєте або вказуєте за замовчуванням, на відміну від найвищого рівня відповіді, де потрібно використовувати "значення" (яке може бути числом).
Встановлення 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 використовує, але вони працюють над першим.
З документації :
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")
]