150 votes

Comment utiliser correctement l'option de champ "choix" dans Django

Je suis en train de lire le tutoriel ici : https://docs.djangoproject.com/en/1.5/ref/models/fields/#choices et j'essaie de créer une boîte où l'utilisateur peut sélectionner le mois de sa naissance. Voici ce que j'ai essayé

 MONTH_CHOICES = (
    (JANUARY, "January"),
    (FEBRUARY, "February"),
    (MARCH, "March"),
    ....
    (DECEMBER, "December"),
)

month = CharField(max_length=9,
                  choices=MONTHS_CHOICES,
                  default=JANUARY)

Est-ce correct ? Je vois que dans le tutoriel que j'ai lu, pour une raison quelconque, ils ont créé les variables en premier, comme ceci

FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'

Pourquoi ont-ils créé ces variables ? Le code que j'ai fourni créerait-il donc une colonne "Choix des mois" dans la base de données appelée "Personnes" et indiquerait-il le mois de naissance de l'utilisateur après qu'il ait cliqué sur l'un des mois et soumis le formulaire ?

10voto

dtar Points 941

Je suggère d'utiliser django-model-utils au lieu de la solution intégrée de Django. Le principal avantage de cette solution est l'absence de duplication des déclarations de chaînes. Tous les éléments de choix sont déclarés une seule fois. C'est également le moyen le plus simple de déclarer des choix utilisant 3 valeurs et de stocker dans la base de données une valeur différente de celle utilisée dans le code source.

from django.utils.translation import ugettext_lazy as _
from model_utils import Choices

class MyModel(models.Model):
   MONTH = Choices(
       ('JAN', _('January')),
       ('FEB', _('February')),
       ('MAR', _('March')),
   )
   # [..]
   month = models.CharField(
       max_length=3,
       choices=MONTH,
       default=MONTH.JAN,
   )

Et avec l'utilisation IntegerField à la place :

from django.utils.translation import ugettext_lazy as _
from model_utils import Choices

class MyModel(models.Model):
   MONTH = Choices(
       (1, 'JAN', _('January')),
       (2, 'FEB', _('February')),
       (3, 'MAR', _('March')),
   )
   # [..]
   month = models.PositiveSmallIntegerField(
       choices=MONTH,
       default=MONTH.JAN,
   )
  • Cette méthode a un petit inconvénient : dans n'importe quel IDE (par exemple PyCharm) il n'y aura pas de complétion de code pour les choix disponibles (c'est parce que ces valeurs ne sont pas des membres standards de la classe Choices).

4voto

Paulo Almeida Points 2355

Vous ne pouvez pas avoir de mots nus dans le code, c'est la raison pour laquelle ils ont créé des variables (votre code échouera avec NameError ).

Le code que vous avez fourni créerait une table de base de données nommée month (plus tout préfixe ajouté par django), parce que c'est le nom de la section CharField .

Mais il existe de meilleures façons de créer les choix particuliers que vous souhaitez. Voir une question précédente sur Stack Overflow .

import calendar
tuple((m, m) for m in calendar.month_name[1:])

2voto

VisioN Points 62518

$ pip install django-better-choices

Pour ceux qui sont intéressés, j'ai créé django-better-choices qui fournit une interface agréable pour travailler avec les choix de Django pour Python 3.7+. Elle supporte les paramètres personnalisés, de nombreuses fonctionnalités utiles et est très conviviale pour les IDE.

Vous pouvez définir vos choix en tant que classe :

from django_better_choices import Choices

class PAGE_STATUS(Choices):
    CREATED = 'Created'
    PENDING = Choices.Value('Pending', help_text='This set status to pending')
    ON_HOLD = Choices.Value('On Hold', value='custom_on_hold')

    VALID = Choices.Subset('CREATED', 'ON_HOLD')

    class INTERNAL_STATUS(Choices):
        REVIEW = 'On Review'

    @classmethod
    def get_help_text(cls):
        return tuple(
            value.help_text
            for value in cls.values()
            if hasattr(value, 'help_text')
        )

Effectuez ensuite les opérations suivantes et beaucoup beaucoup plus :

print( PAGE_STATUS.CREATED )                # 'created'
print( PAGE_STATUS.ON_HOLD )                # 'custom_on_hold'
print( PAGE_STATUS.PENDING.display )        # 'Pending'
print( PAGE_STATUS.PENDING.help_text )      # 'This set status to pending'

'custom_on_hold' in PAGE_STATUS.VALID       # True
PAGE_STATUS.CREATED in PAGE_STATUS.VALID    # True

PAGE_STATUS.extract('CREATED', 'ON_HOLD')   # ~= PAGE_STATUS.VALID

for value, display in PAGE_STATUS:
    print( value, display )

PAGE_STATUS.get_help_text()
PAGE_STATUS.VALID.get_help_text()

Et bien sûr, il est entièrement pris en charge par Django et Django Migrations :

class Page(models.Model):
    status = models.CharField(choices=PAGE_STATUS, default=PAGE_STATUS.CREATED)

Documentation complète ici : https://pypi.org/project/django-better-choices/

Prograide.com

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.

Powered by:

X