Comment procéder pour spécifier et utiliser un ENUM dans un modèle Django ?
Cela n'empêche pas les valeurs "fausses" d'être enregistrées si elles n'ont pas été nettoyées auparavant, n'est-ce pas ?
Comment procéder pour spécifier et utiliser un ENUM dans un modèle Django ?
Desde el Documentation sur Django :
MAYBECHOICE = (
('y', 'Yes'),
('n', 'No'),
('u', 'Unknown'),
)
Et vous définissez un champ de char dans votre modèle :
married = models.CharField(max_length=1, choices=MAYBECHOICE)
Vous pouvez faire de même avec des champs entiers si vous n'aimez pas avoir de lettres. dans votre base de données.
Dans ce cas, réécrivez vos choix :
MAYBECHOICE = (
(0, 'Yes'),
(1, 'No'),
(2, 'Unknown'),
)
Cela n'empêche pas les valeurs "fausses" d'être enregistrées si elles n'ont pas été nettoyées auparavant, n'est-ce pas ?
@Strayer : oui, je suppose que cela n'est utile que pour l'utilisation de formulaires modèles.
Notez que le style Django recommandé implique que les caractères doivent être des constantes : docs.djangoproject.com/fr/dev/internals/contributing/
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) )
Utilisation de la choices
n'utilisera pas le type de données ENUM ; il créera simplement un VARCHAR ou un INTEGER, selon que vous utilisez ou non le paramètre choices
avec un CharField ou un IntegerField. En général, c'est très bien. S'il est important pour vous que le type ENUM soit utilisé au niveau de la base de données, vous avez trois options :
Avec l'une ou l'autre de ces options, il vous incombe de gérer les implications de la portabilité entre les bases de données. Dans l'option 2, vous pourriez utiliser SQL personnalisé spécifique à la base de données pour s'assurer que votre ALTER TABLE n'est exécuté que sur MySQL. Dans l'option 3, votre méthode db_type devrait vérifier le moteur de la base de données et définir le type de colonne db à un type qui existe réellement dans cette base de données.
UPDATE : Depuis que le framework de migrations a été ajouté dans Django 1.7, les options 1 et 2 ci-dessus sont entièrement obsolètes. L'option 3 a toujours été la meilleure de toute façon. La nouvelle version des options 1/2 impliquerait une migration personnalisée complexe utilisant SeparateDatabaseAndState
-- mais vous voulez vraiment l'option 3.
Réglage de choices
sur le champ permettra une certaine validation du côté de Django, mais elle ne le fera pas définir toute forme d'un type énuméré du côté de la base de données.
Comme d'autres l'ont mentionné, la solution consiste à spécifier db_type
sur un champ personnalisé.
Si vous utilisez un backend SQL (par exemple MySQL), vous pouvez procéder comme suit :
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)
Exécuter syncdb
et inspectez votre tableau pour voir si le ENUM
a été créé correctement.
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 | |
+--------+-----------------------------+------+-----+---------+----------------+
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:
Il s'agit d'une autre façon simple et agréable d'implémenter les enums, bien qu'elle ne permette pas vraiment de sauvegarder les enums dans la base de données.
Toutefois, elle vous permet de faire référence à l'"étiquette" lorsque vous effectuez une requête ou que vous spécifiez des valeurs par défaut, contrairement à la réponse la mieux notée où vous devez utiliser la "valeur" (qui peut être un nombre).
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
4 votes
Steve, si vous voulez dire utiliser le type ENUM de MySQL, alors vous n'avez pas de chance, pour autant que je sache Django ne fournit pas de support pour cela (cette fonctionnalité n'est pas disponible dans toutes les bases de données supportées par Django). La réponse fournie par Paul fonctionne, mais elle ne le fera pas définir le type dans la BD.