Сведения о вопросе

Martincow

21:40, 9th August, 2020

Теги

python   mysql   django   django-models   enums    

Указание перечисления mySQL в модели Django

Просмотров: 582   Ответов: 8

Как мне определить и использовать ENUM в модели Django?



  Сведения об ответе

park

14:02, 3rd August, 2020

Из документации Django :

MAYBECHOICE = (
    ('y', 'Yes'),
    ('n', 'No'),
    ('u', 'Unknown'),
)

И вы определите страничке в вашей модели :

married = models.CharField(max_length=1, choices=MAYBECHOICE)

Вы можете сделать то же самое с целочисленными полями, если вам не нравится иметь буквы в вашем БД.

В этом случае перепишите свой выбор:

MAYBECHOICE = (
    (0, 'Yes'),
    (1, 'No'),
    (2, 'Unknown'),
)


  Сведения об ответе

ITSME

13:23, 1st August, 2020

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) )


  Сведения об ответе

FAriza

06:14, 13th August, 2020

Использование параметра choices не будет использовать тип ENUM db; он просто создаст VARCHAR или INTEGER, в зависимости от того, используете ли вы choices с CharField или IntegerField. В общем, это просто замечательно. Если для вас важно, чтобы тип ENUM использовался на уровне базы данных, у вас есть три варианта:

  1. Использовать "./manage.py sql appname " чтобы увидеть генерируемый файл SQL Django, вручную измените его, чтобы использовать тип ENUM, и запустите его самостоятельно. Если вы сначала создадите таблицу вручную,"./manage.py syncdb " не будет возиться с этим.
  2. Если вы не хотите делать это вручную каждый раз, когда вы создаете свой DB, поместите некоторые пользовательские SQL в appname/sql/modelname.sql, чтобы выполнить соответствующую команду ALTER TABLE.
  3. Создайте пользовательский тип поля и соответствующим образом определите метод db_type.

При любом из этих вариантов вы несете ответственность за последствия для переносимости данных между базами данных. В Варианте 2 вы можете использовать database-backend-specific custom SQL , чтобы гарантировать, что ваша ALTER-таблица выполняется только на MySQL. В варианте 3 Ваш метод db_type должен был бы проверить компонент database engine и установить тип столбца db для типа, который фактически существует в этой базе данных.

UPDATE: поскольку структура миграции была добавлена в Django 1.7, варианты 1 и 2 выше полностью устарели. Вариант 3 всегда был лучшим вариантом в любом случае. Новая версия options 1/2 будет включать сложную пользовательскую миграцию с использованием SeparateDatabaseAndState -- но на самом деле вы хотите Вариант 3.


  Сведения об ответе

+-*/

06:09, 9th August, 2020

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 в базе данных.

Однако он позволяет вам ссылаться на 'label' всякий раз, когда вы задаете запрос или задаете значения по умолчанию, в отличие от ответа с самым высоким рейтингом, где вы должны использовать 'value' (который может быть числом).


  Сведения об ответе

lool

09:19, 17th August, 2020

Установка значения 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    |                |
+--------+-----------------------------+------+-----+---------+----------------+


  Сведения об ответе

lesha

16:34, 9th August, 2020

Если вы действительно хотите использовать свои базы данных ENUM типа:

  1. Используйте Django 1.x
  2. Распознать ваше приложение будет работать только на некоторых базах данных.
  3. Головоломка через эту страницу документации: http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields

Удачи вам!


  Сведения об ответе

lourence

06:53, 17th August, 2020

В настоящее время существует два проекта github, основанных на добавлении этих элементов, хотя я не изучал, как именно они реализуются:

  1. Django-EnumField :
    Предоставляет поле модели перечисления Django (с использованием IntegerField) с многократно используемым enums и проверкой перехода.
  2. Django-EnumFields :
    Этот пакет позволяет использовать real Python (pep435-style) enums с Django.

Я не думаю, что они используют DB типов перечисления, но они находятся в работе для первого из них.


  Сведения об ответе

dumai

13:03, 4th August, 2020

А в верхней части вашего файла models.py добавьте эту строку после выполнения импорта:

    enum = lambda *l: [(s,_(s)) for s in l]


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться