Manejo de Enums con Django



@eduardo_gpg

Número de visitas 1979

Tiempo de lectura 2 min

7 Diciembre 2021

Para este vídeos hablaremos acerca de cómo podemos implementar Enums en nuestros modelos Django; pudiendo así crear formularios con inputs de tipo select, y por supuesto, limitando la cantidad de valores que podemos almacenar. 😎 Para este tutorial estaré trabajando con el modelo Transaction.

class Transaction(models.Model):
    pass

Donde una transacción puede encontrarse en alguno de los siguientes estados.

  • CREATED
  • COMPLETED
  • FAILED

Por default, siempre que se cree una nueva transacción, el estatus comenzará en CREATED. Y para poder lograr esto haremos uso de Enums.

Recordando que los Enums permiten limitar la cantidad de opciones que podemos almacenar para nuestras columnar, evitando así redundancia y una posible inconsistencia de datos.

Bien, una vez dicho todo esto, y sin más introducción, comencemos con el tutorial.

Listado de opciones

Lo primero que debemos tener en claro es el tipo de datos que deseamos almacenar. Para fines prácticos, les recomiendo ampliamente trabajemos con datos de tipo entero. De esta forma será mucho más sencillo poder representar y conocer los estados de nuestros modelos.

En mi caso los estados quedarían de la siguiente manera.

  • CREATED = 0
  • COMPLETED = 1
  • FAILED = 2

Por lo tanto, si vamos a almacenar números enteros, lo recomendable es utilizar la clase PositiveIntegerField, clase la cual posee el parámetro choices. Será a partir de este parámetro que nosotros podremos delimitar las opciones que pueden ser almacenadas en nuestra tabla.

Listo, una vez hemos definido el tipo, lo siguiente que debemos hacer será crear una Sub-Clase con cada una de las opciones y correspondientes valores.

Con esto en mente, mi clase pudiera quedar de la siguiente manera.

from django.utils.translation import gettext_lazy as _

class Transaction(models.Model):

    class State(models.IntegerChoices):
        CREATED = 0, _('Creado')
        COMPLETED = 1, _('Completado')
        FAILED = 2, _('Fallido')

    state = models.IntegerField(default=Status.CREATED, choices=Status.choices)

Aquí hay que destacar un par de cosas. La primera es la necesidad de importar la función gettext lazy y renombrarla como un guión bajo (_) esto, principalmente, por temas de legibilidad. Esta función nos permitirá definir el texto que se mostrará al momento de pintar nuestro input de tipo select.

Además de ellos es necesario de crear una constante de tipo tupla para nuestra subclase por cada una de las opciones.

Será a partir de estas constantes que podremos limitar los valores que vamos a almacenar.

Las tuplas deberán almacenar únicamente 2 valores. El valor que se va almacenar en la tabla y el valor que deseemos se muestre en el formulario.

Listo, pongamos esto a prueba. Intentemos crear y obtener un par de registros utilizando las opciones.

Estatus por default

>>> transaction = Transaction.objects.create()
>>> transaction.state
<State.CREATED: 0>

Definimos un estatus.

>>> credit = Credit.objects.create(client_id=1, state=Credit.State.COMPLETED)
>>> transaction.state
<State.COMPLETED: 1>

Obtenemos registros con respecto a un estatus.

>>> Credit.objects.filter(state=Credit.State.CREATED)
<QuerySet [<Credit: 1>, <Credit: 2>, <Credit: 3>, <Credit: 4>]>

Perfecto, ya podemos tanto crear como obtener registros a partir de nuestras opciones. Bastante sencillo ¿No lo crees? Ahora pasemos a crear y pintar nuestro formulario.

Formulario

Para nuestro formulario, lo primero que debemos hacer será crear nuestra clase ModelForm. Les recomiendo que lo hagamos en un nuevo archivo llamado forms.py.

Es algo bastante sencillo.

from django.forms import ModelForm

from .models import Credit

class CreditForm(ModelForm):
    class Meta:
        model = Credit
        fields = ['state']
        labels = { 'state': 'Estado actual' }

    def __init__(self, *args, **kwargs):
        super(CreditForm, self).__init__(*args, **kwargs)

Por default Django tomará el texto definido por la función gettext lazy y usará este texto para pintar las opciones en el input.

ejemplo

Conclusión

En conclusión, como pudimos observar, para estas nuevas versiones de Django el poder implementar "Enums" como un listado de opciones es sumamente sencillo. Basta con crear una nueva sub clase de tipo IntegerChoices o TextChoices (Dependiendo del caso) y listo.


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login

Hector.Ferrada

Hola, tengo una duda y no sé si estoy bien o mal, en el modelo, defines una subclase con nombre State pero cuando se aplica al atributo la referencias como Status... será que Status es palabra reservada de Choices o simplemente es un error de tipeo y en definitiva debería decir State y no Status.

Ejemplo: (iría State como se llama la subclase o Status, no sé de dónde viene.🤔) models.IntegerField(default=State.CREATED, choices=State.choices)

Espero me puedas contestar. Te agradezco.

Más Tips y Ejercicios 🐍

Adquiere una subscripción PyWombat por tan solo $3 USD. al mes.

Conoce los beneficios de ser usuario premium:
Niveles desbloqueados: Ten accesos a todos los niveles de ejercicios. 🔓
Nuevo límite: Incrementa tu límite de ejercicios por semana. 🚀
Contenido único: Recibe semanalmente recursos exclusivos de Python (Videos, Artículos y Capitulos del libro PyWombat, comienza como desarrollador Python. 🐍