Стив, если вы имели в виду использование типа MySQL ENUM, то вам не повезло, насколько я знаю, Django не поддерживает это (эта функция доступна не во всех БД, поддерживаемых Django). Ответ, предоставленный Полом, работает, но он не определяет тип в БД.
Как сказал @Carl Meyer в своем ответе, это НЕ создает столбец ENUM в базе данных. Он создает столбец VARCHAR или INTEGER, поэтому на самом деле не отвечает на вопрос.
Ариэль
Могу ли я добавить функцию выбора с целочисленным полем? @fulmicoton
Ильяс
36
from django.db import models
classEnumField(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)
defdb_type(self):return"enum({0})".format( ','.join("'%s'" % v for v in self.values) )
Начиная с django 1.2, вам нужно добавить второй параметр, соединение, к db_type def.
Hans Lawrenz
2
Что же тогда случилось с codecatelog? Локосу это могло быть хорошей идеей ... Теперь я получаю 404 - даже для корневой страницы.
Дэнни Стейпл
33
Использование choicesпараметра не будет использовать тип базы данных ENUM; он просто создаст VARCHAR или INTEGER, в зависимости от того, используете ли вы choicesс CharField или IntegerField. В общем, это нормально. Если для вас важно, чтобы тип ENUM использовался на уровне базы данных, у вас есть три варианта:
Используйте "./manage.py sql appname", чтобы увидеть SQL, сгенерированный Django, вручную измените его, чтобы использовать тип ENUM, и запустите его самостоятельно. Если вы сначала создадите таблицу вручную, "./manage.py syncdb" не повредит ей.
Если вы не хотите делать это вручную каждый раз при создании своей БД, поместите некоторый пользовательский SQL в appname / sql / modelname.sql, чтобы выполнить соответствующую команду ALTER TABLE.
При использовании любого из этих вариантов вы должны будете устранить последствия для переносимости между базами данных. В варианте 2 вы можете использовать специальный SQL для базы данных, чтобы ваша ALTER TABLE работала только в MySQL. В варианте 3 ваш метод db_type должен будет проверить механизм базы данных и установить тип столбца db на тип, который действительно существует в этой базе данных.
ОБНОВЛЕНИЕ : поскольку фреймворк миграции был добавлен в Django 1.7, варианты 1 и 2 выше полностью устарели. В любом случае вариант 3 всегда был лучшим вариантом. Новая версия вариантов 1/2 предполагает сложную пользовательскую миграцию с использованием SeparateDatabaseAndState- но на самом деле вам нужен вариант 3.
Это еще один приятный и простой способ реализации перечислений, хотя на самом деле он не сохраняет перечисления в базе данных.
Однако он позволяет вам ссылаться на «метку» при запросе или указании значений по умолчанию, в отличие от ответа с наивысшим рейтингом, где вы должны использовать «значение» (которое может быть числом).
Установка choicesв поле позволит выполнить некоторую проверку на стороне Django, но не будет определять какую-либо форму перечислимого типа на стороне базы данных.
Как уже упоминали другие, решение состоит в том, чтобы указать db_type настраиваемое поле.
Если вы используете серверную часть SQL (например, MySQL), вы можете сделать это так:
from django.db import models
classEnumField(models.Field):def__init__(self, *args, **kwargs):
super(EnumField, self).__init__(*args, **kwargs)
assert self.choices, "Need choices for enumeration"defdb_type(self, connection):ifnot 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))
classIceCreamFlavor(EnumField, models.CharField):def__init__(self, *args, **kwargs):
flavors = [('chocolate', 'Chocolate'),
('vanilla', 'Vanilla'),
]
super(IceCreamFlavor, self).__init__(*args, choices=flavors, **kwargs)
classIceCream(models.Model):
price = models.DecimalField(max_digits=4, decimal_places=2)
flavor = IceCreamFlavor(max_length=20)
Запустите syncdbи проверьте свою таблицу, чтобы убедиться, что файл ENUMбыл создан правильно.
mysql> SHOWCOLUMNSIN 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 | |
+--------+-----------------------------+------+-----+---------+----------------+
Очень полезный ответ! Но для PostgreSQL это не сработает. Причина в том, что PostgreSQL ENUM не поддерживает значение по умолчанию. В PostgreSQL сначала нужно создать CREATE DOMAIN или CREATE TYPE. Reff 8.7. Перечисленные типы Я попробовал трюк @David, и он отлично работает с MySQL, но в PostgrSQL работа заканчивается ошибкой 'type "enum" does not exist LINE 1: ....tablename" ADD COLUMN "select_user" ENUM('B', ...'.
Grijesh Chauhan
6
Если вы действительно хотите использовать свои базы данных типа ENUM:
Используйте Django 1.x
Знайте, что ваше приложение будет работать только с некоторыми базами данных.
В настоящее время существует два проекта github, основанных на их добавлении, хотя я не разбирался в том, как они реализованы:
Django-EnumField :
предоставляет поле модели Django перечисления (с использованием IntegerField) с многократно используемыми перечислениями и проверкой перехода.
Django-EnumFields :
этот пакет позволяет использовать настоящие перечисления Python (в стиле PEP435) с Django.
Я не думаю, что они используют типы перечислений БД, но они работают над первым.
Теперь имейте в виду, что он не требует выбора на уровне базы данных, это конструкция только для Python. Если вы хотите также применить это значение в базе данных, вы можете объединить это с ограничениями базы данных:
Ответы:
Из документации Django :
И вы определяете charfield в своей модели:
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; он просто создаст 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/
Это еще один приятный и простой способ реализации перечислений, хотя на самом деле он не сохраняет перечисления в базе данных.
Однако он позволяет вам ссылаться на «метку» при запросе или указании значений по умолчанию, в отличие от ответа с наивысшим рейтингом, где вы должны использовать «значение» (которое может быть числом).
источник
Установка
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, основанных на их добавлении, хотя я не разбирался в том, как они реализованы:
предоставляет поле модели Django перечисления (с использованием IntegerField) с многократно используемыми перечислениями и проверкой перехода.
этот пакет позволяет использовать настоящие перечисления Python (в стиле PEP435) с Django.
Я не думаю, что они используют типы перечислений БД, но они работают над первым.
источник
Django 3.0 имеет встроенную поддержку Enums
Из документации :
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]
источник