web-dev-qa-db-fra.com

Comment utiliser les énumérations comme champ de choix dans le modèle Django

J'ai une classe modèle dont je veux que deux champs soient des champs de choix, donc pour remplir ces choix, j'utilise une énumération comme indiqué ci-dessous

#models.py
class Transaction(models.Model):
    trasaction_status = models.CharField(max_length=255, choices=TransactionStatus.choices())
    transaction_type = models.CharField(max_length=255, choices=TransactionType.choices())

#enums.py
class TransactionType(Enum):

    IN = "IN",
    OUT = "OUT"

    @classmethod
    def choices(cls):
        print(Tuple((i.name, i.value) for i in cls))
        return Tuple((i.name, i.value) for i in cls)

class TransactionStatus(Enum):

    INITIATED = "INITIATED",
    PENDING = "PENDING",
    COMPLETED = "COMPLETED",
    FAILED = "FAILED"
    ERROR = "ERROR"

    @classmethod
    def choices(cls):
        print(Tuple((i.name, i.value) for i in cls))
        return Tuple((i.name, i.value) for i in cls)

Cependant, lorsque j'essaie d'accéder à ce modèle via l'administrateur, j'obtiens l'erreur suivante:

Django Version: 1.11
Exception Type: ValueError
Exception Value:    
too many values to unpack (expected 2)

J'ai suivi deux articles qui décrivaient comment utiliser les énumérations:

16
Paras

Pour Django 2.x et inférieur:

Vous définissez un Enum en définissant les différentes options comme indiqué ici :

class TransactionStatus(Enum):

    INITIATED = "INITIATED"
    PENDING = "PENDING"
    COMPLETED = "COMPLETED"
    FAILED = "FAILED"
    ERROR = "ERROR"

Notez qu'il n'y a pas de virgule! Cela vous permet plus tard dans votre code de faire référence à TransactionStatus.ERROR ou TransactionStatus.PENDING.

Le reste de votre code est correct. Vous obtenez le choices en créant des tuples de option.name, option.value.

MISE À JOUR: Pour Django 3.x et supérieur , utilisez les types intégrés TextChoices, IntegerChoices et Choices comme décrit ici . De cette façon, vous n'avez pas à construire vous-même le choices Tuple.

9
dirkgroten

Django 3.0 a un support intégré pour Enums

Exemple:

from Django.utils.translation import gettext_lazy as _

class Student(models.Model):

    class YearInSchool(models.TextChoices):
        FRESHMAN = 'FR', _('Freshman')
        SOPHOMORE = 'SO', _('Sophomore')
        JUNIOR = 'JR', _('Junior')
        SENIOR = 'SR', _('Senior')
        GRADUATE = 'GR', _('Graduate')

    year_in_school = models.CharField(
        max_length=2,
        choices=YearInSchool.choices,
        default=YearInSchool.FRESHMAN,
    )

Ceux-ci fonctionnent de manière similaire à enum de la bibliothèque standard de Python, mais avec quelques modifications:

  • Les valeurs de membre Enum sont un tuple d'arguments à utiliser lors de la construction du type de données concret. Django prend en charge l'ajout d'une valeur de chaîne supplémentaire à la fin de ce tuple à utiliser comme nom lisible par l'homme, ou label. Le label peut être un chaîne traduisible paresseuse. Ainsi, dans la plupart des cas, la valeur du membre sera un (value, label) deux-Tuple. Si aucun Tuple n'est fourni, ou si le dernier élément n'est pas une chaîne (paresseuse), l'étiquette est - généré automatiquement à partir du nom du membre.
  • Une propriété .label Est ajoutée aux valeurs, pour renvoyer le nom lisible par l'homme. Un certain nombre de propriétés personnalisées sont ajoutées aux classes d'énumération - .choices, .labels, .values Et .names - pour faciliter l'accès aux listes de ces parties distinctes de l'énumération. Utilisez .choices Comme valeur appropriée pour passer aux choix dans une définition de champ.
  • L'utilisation de enum.unique() est appliquée pour garantir que les valeurs ne peuvent pas être définies plusieurs fois. Il est peu probable que cela soit prévu dans les choix d'un champ.

Pour plus d'informations, consultez la documentation

22
Cesar Canassa

Le problème dans votre code est que INITIATED = "INITIATED", une virgule après l'option INITIATED et d'autres options. lorsque nous ajoutons une virgule après une chaîne, elle devient un tuple. Voir un exemple ci-dessous

s = 'my str'
print(type(s))
# output: str

s = 'my str',
print(type(s))
# output: Tuple

models.py

class Transaction(models.Model):
    trasaction_status = models.CharField(max_length=255, choices=TransactionStatus.choices())
    transaction_type = models.CharField(max_length=255, choices=TransactionType.choices())

enums.py

class TransactionType(Enum):

    IN = "IN"
    OUT = "OUT"

    @classmethod
    def choices(cls):
        print(Tuple((i.name, i.value) for i in cls))
        return Tuple((i.name, i.value) for i in cls)

class TransactionStatus(Enum):

    INITIATED = "INITIATED"
    PENDING = "PENDING"
    COMPLETED = "COMPLETED"
    FAILED = "FAILED"
    ERROR = "ERROR"

    @classmethod
    def choices(cls):
        print(Tuple((i.name, i.value) for i in cls))
        return Tuple((i.name, i.value) for i in cls)
2
anjaneyulubatta505