Especificando um mySQL ENUM em um modelo de Django

votos
81

Como faço para ir sobre como especificar e usando um ENUM em um modelo de Django?

Publicado 22/08/2008 em 00:48
fonte usuário
Em outras línguas...                            


8 respostas

votos
95

A partir da documentação do Django :

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

E você definir um CharField em seu modelo:

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

Você pode fazer o mesmo com campos inteiro se você não gostaria de ter letras em seu db.

Nesse caso, reescrever suas escolhas:

MAYBECHOICE = (
    (0, 'Yes'),
    (1, 'No'),
    (2, 'Unknown'),
)
Respondeu 22/08/2008 em 00:54
fonte usuário

votos
35
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) )
Respondeu 07/10/2009 em 11:47
fonte usuário

votos
29

Usando o choicesparâmetro não vai usar o tipo ENUM db; ele só irá criar um VARCHAR ou inteiro, dependendo se você usar choicescom um CharField ou IntegerField. Geralmente, isso é apenas multa. Se é importante para você que o tipo ENUM é usado no nível de banco de dados, você tem três opções:

  1. Use "appname sql ./manage.py" para ver o Django SQL gera, manualmente modificá-lo para usar o tipo ENUM, e executá-lo a si mesmo. Se você criar a tabela manualmente em primeiro lugar, "syncdb ./manage.py" não vai mexer com ele.
  2. Se você não quiser fazer isso manualmente toda vez que você gerar o seu DB, colocar um pouco de SQL personalizada no appname / sql / modelname.sql para executar o comando ALTER TABLE apropriada.
  3. Criar um tipo de campo personalizado e definir o método db_type adequadamente.

Com qualquer uma dessas opções, seria sua a responsabilidade de lidar com as implicações para a portabilidade entre bancos de dados. Na opção 2, você poderia usar banco de dados específico do SQL back-end personalizado para garantir o seu ALTER TABLE só é executado em MySQL. Na opção 3, o seu método db_type seria necessário verificar o motor de banco de dados e definir o tipo de coluna db para um tipo que realmente existe no banco de dados.

ATUALIZAÇÃO : Como o quadro migrações foi adicionado em Django 1.7, as opções 1 e 2 acima são totalmente obsoletos. Opção 3 foi sempre a melhor opção de qualquer maneira. A nova versão de opções 1/2 envolveria uma migração personalizada complexa usando SeparateDatabaseAndState- mas realmente você quer a opção 3.

Respondeu 29/08/2008 em 04:57
fonte usuário

votos
9

Definir choicesno campo permitirá que alguma validação na extremidade Django, mas não vai definir qualquer forma de um tipo enumerado na extremidade do banco de dados.

Como já foi mencionado, a solução é especificar db_typeem um campo personalizado.

Se você estiver usando um backend SQL (por exemplo, MySQL), você pode fazer isso assim:

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)

Executar syncdbe inspecionar sua tabela para ver que o ENUMfoi criado corretamente.

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    |                |
+--------+-----------------------------+------+-----+---------+----------------+
Respondeu 27/09/2013 em 00:38
fonte usuário

votos
8

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:

Esta é outra maneira agradável e fácil de implementar enums embora não realmente salvar enums no banco de dados.

No entanto, não permitem que você faça referência a 'label' sempre que consultar ou especificar padrões em oposição à resposta com a melhor nota onde você tem que usar o 'valor' (que pode ser um número).

Respondeu 26/10/2012 em 16:03
fonte usuário

votos
6

Se você realmente quiser usar o seu tipo de bases de dados ENUM:

  1. Use Django 1.x
  2. Reconhecer a sua aplicação só irá funcionar em alguns bancos de dados.
  3. Quebra-cabeça através desta página documentação: http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields

Boa sorte!

Respondeu 02/12/2008 em 19:21
fonte usuário

votos
3

Não está actualmente dois projectos github com base em adicionar estes, embora eu não olhei para exatamente como elas são implementadas:

  1. Django-EnumField :
    Fornece uma enumeração Django campo modelo (usando IntegerField) com enumerações reutilizáveis e validação de transição.
  2. Django-EnumFields :
    Este pacote permite que você use Python real (PEP435-style) enums com Django.

Eu não acho que qualquer um usar tipos enum DB, mas eles estão em obras para primeiro.

Respondeu 09/02/2015 em 11:23
fonte usuário

votos
-2

A parte superior do seu arquivo models.py, adicione esta linha depois de fazer suas importações:

    enum = lambda *l: [(s,_(s)) for s in l]
Respondeu 03/03/2014 em 20:18
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more