Lorsque vous avez un champ de modèle avec une option de choix, vous avez tendance à avoir des valeurs magiques associées à des noms lisibles par l'homme. Existe-t-il dans Django un moyen pratique de définir ces champs par le nom lisible par l'homme au lieu de la valeur?
Considérez ce modèle:
class Thing(models.Model):
PRIORITIES = (
(0, 'Low'),
(1, 'Normal'),
(2, 'High'),
)
priority = models.IntegerField(default=0, choices=PRIORITIES)
À un moment donné, nous avons une instance Thing et nous voulons définir sa priorité. Evidemment tu pourrais faire,
thing.priority = 1
Mais cela vous oblige à mémoriser le mappage Valeur-Nom des PRIORITÉS. Cela ne fonctionne pas:
thing.priority = 'Normal' # Throws ValueError on .save()
Actuellement, j'ai cette solution de contournement stupide:
thing.priority = dict((key,value) for (value,key) in Thing.PRIORITIES)['Normal']
mais c'est maladroit. Étant donné la fréquence de ce scénario, je me demandais si quelqu'un avait une meilleure solution. Existe-t-il une méthode de champ pour définir les champs par nom de choix que j'ai totalement négligé?
la source
J'aurais probablement configuré le dict de recherche inversée une fois pour toutes, mais si je ne l'avais pas fait, j'utiliserais simplement:
ce qui semble plus simple que de construire le dict à la volée juste pour le jeter à nouveau ;-).
la source
Voici un type de champ que j'ai écrit il y a quelques minutes qui, je pense, fait ce que vous voulez. Son constructeur nécessite un argument 'choix', qui peut être soit un tuple de 2-tuples dans le même format que l'option de choix d'IntegerField, soit une simple liste de noms (ie ChoiceField (('Low', 'Normal', 'High'), par défaut = 'Low')). La classe s'occupe du mappage de string à int pour vous, vous ne voyez jamais le int.
la source
J'apprécie la manière constante de définir, mais je pense que le type Enum est de loin le meilleur pour cette tâche. Ils peuvent représenter un entier et une chaîne pour un élément dans le même temps, tout en gardant votre code plus lisible.
Les énumérations ont été introduites dans Python dans la version 3.4. Si vous utilisez un bas (comme 2.x) , vous pouvez toujours en installant le package rétroportés :
pip install enum34
.C'est à peu près tout. Vous pouvez hériter de
ChoiceEnum
pour créer vos propres définitions et les utiliser dans une définition de modèle comme:Interroger est la cerise sur le gâteau comme vous pouvez le deviner:
Les représenter en chaîne est également simplifié:
la source
ChoiceEnum
, vous pouvez utiliser.value
et.name
comme le décrit @kirpit et remplacer l'utilisation dechoices()
par -tuple([(x.value, x.name) for x in cls])
soit dans une fonction (DRY) ou directement dans le constructeur du champ.Utilisez-le comme ceci:
la source
Depuis Django 3.0, vous pouvez utiliser:
la source
Remplacez simplement vos chiffres par les valeurs lisibles par l'homme que vous souhaitez. En tant que tel:
Cela le rend lisible par l'homme, cependant, vous devrez définir votre propre ordre.
la source
Ma réponse est très tardive et peut sembler évidente aux experts de Django d'aujourd'hui, mais pour quiconque atterrit ici, j'ai récemment découvert une solution très élégante apportée par django-model-utils: https://django-model-utils.readthedocs.io/ fr / latest / utilities.html # choix
Ce package vous permet de définir des choix avec trois tuples où:
Alors, voici ce que vous pouvez faire:
Par ici:
Prendre plaisir :)
la source
priority = models.IntegerField(default=PRIORITIES.Low, choices=PRIORITIES)
(il va sans dire que l'affectation de priorité doit être indentée pour être à l'intérieur de la classe Thing pour ce faire). Pensez également à utiliser des mots / caractères minuscules pour l'identifiant python, car vous ne faites pas référence à une classe, mais à un paramètre à la place (vos choix deviendraient alors:(0, 'low', 'Low'),
et ainsi de suite).À l'origine, j'ai utilisé une version modifiée de la réponse de @ Allan:
Simplifié avec le
django-enumfields
package package que j'utilise maintenant:la source
L'option de choix du modèle accepte une séquence constituée elle-même d'itérables d'exactement deux éléments (par exemple [(A, B), (A, B) ...]) à utiliser comme choix pour ce champ.
De plus, Django fournit des types d'énumération que vous pouvez sous-classer pour définir des choix de manière concise:
Django prend en charge l'ajout d'une valeur de chaîne supplémentaire à la fin de ce tuple à utiliser comme nom ou étiquette lisible par l'homme. L'étiquette peut être une chaîne traduisible paresseusement.
Remarque: vous pouvez l' utiliser à l' aide
ThingPriority.HIGH
,ThingPriority.['HIGH']
ouThingPriority(0)
d'accéder ou de consultation des membres de ENUM.la source