Signals en Django

- Andrés Cruz

In english
Signals en Django

Este material forma parte de mi curso y libro completo; puedes adquirirlos desde el apartado de libros y/o cursos Curso y libro desarrollo web con Django 5 y Python 3 + integración con Vue 3, Bootstrap y Alpine.js.

Django incluye un paquete para manejar las señales o Signals de la aplicación, con las cuales es posible que la aplicación pueda recibir notificaciones cuando ocurren determinadas acciones en la aplicación, como crear un post, registrar un usuario entre otro, cuando sucede alguna de estas acciones, podemos disparar esta señal para ejecutar una función que realizar alguna acción como registrar un log, enviar un correo electrónico, entre otros.

Los Signals no son más que eventos o mensajeros configurables que informan sobre eventos importantes en nuestra aplicación, son una forma de comunicación entre diferentes partes de la aplicación. En este capítulo, explicaremos qué son los Signals, cómo funcionan y cómo puedes aprovecharlos para mantener tu código organizado y eficiente.

Los Signals son una forma de comunicación entre diferentes partes de tu aplicación, con los signals, es posible notificar a un conjunto de receptores que algo ha ocurrido.

Como ejemplo, suponiendo que tenemos un blog y quieres enviar un correo electrónico cada vez que alguien se registra, podemos emplear los Signals en Django, el evento viene siendo el registro del evento que dispara una señal que es conectada a una función que es la que envía el correo electrónico; esta acción puede ser cualquier otra operación como enviar alguna notificación u otra tarea personalizada.

El uso de los signas es muy fácil, tan solo debemos de crear una función que es la que se debe de ejecutar cuando suceda el evento, esta función es el receive o la que recibe, y la misma la especificamos mediante el decorador from django.dispatch import receiver el cual, le establecemos dos parámetros, el tipo de signal y el modelo.

Tipos Signals

Tenemos distintos tipos de signals, todos ellos puedes emplearlos para realizar acciones personalizadas antes/después de realizar las acciones correspondientes y los podemos clasificar en cinco tipos:

  1. Para los modelos
  2. Migraciones
  3. Peticiones/respuestas
  4. Pruebas
  5. Base de datos

Model Signals

Signals relacionados con los modelos:

  • pre_init: Se activa justo antes de que se cree una nueva instancia del modelo asociado. 
  • post_init: Se activa después de que se haya creado una nueva instancia de un modelo.
  • pre_save: Se activa antes de guardar una instancia de un modelo en la base de datos.
  • post_save: Se ejecuta después de que se haya guardado una instancia de un modelo en la base de datos. Es útil para realizar acciones posteriores al guardado, como enviar notificaciones o actualizar modelos relacionados.
  • pre_delete: Se dispara antes de eliminar una instancia de un modelo. Puedes usarlo para realizar acciones previas a la eliminación, como liberar recursos o registros relacionados.
  • post_delete: Se ejecuta después de eliminar una instancia de un modelo. Puedes usarlo para realizar tareas posteriores a la eliminación, como liberar recursos o registros relacionados.
  • m2m_changed: Este signal se activa cuando se modifican las relaciones de muchos a muchos (ManyToMany)
  • class_prepared: Se dispara cuando una clase de modelo está completamente preparada y lista para su uso. Puedes usarlo para realizar configuraciones adicionales en las clases de modelo.

Migrations Signals

Signals relacionados con las migraciones:

  • pre_migrate: Se ejecuta antes de aplicar las migraciones en la base de datos. 
  • post_migrate: Se activa después de aplicar las migraciones en la base de datos. Puedes usarlo para realizar acciones posteriores a la migración, como cargar datos iniciales o actualizar esquemas.

Request/Response Signals

Signals relacionados con las peticiones y respuestas HTTP:

  • request_started: Se dispara al inicio de una solicitud HTTP.
  • request_finished: Se ejecuta al finalizar una solicitud HTTP.
  • got_request_exception: Se activa cuando ocurre una excepción durante el procesamiento de una solicitud. Útil para manejar errores y registrar la excepción en un log.

Test Signals

Signals relacionados con pruebas unitarias:

  1. setting_changed: Esta señal se envía cuando se cambia el valor de una configuración (setting). Útil para manejar cambios en las configuraciones de la aplicación durante las pruebas.
  2. template_rendered: Se envía cuando el sistema de prueba renderiza una plantilla.

Database Wrappers

Signals relacionado con las conexiones de la base de datos:

  1. connection_created: Se activa cuando se establece una conexión a una base de datos.

Al recibir estos signals tiene parámetros específicos que puedes explorar en la documentación oficial:

https://docs.djangoproject.com/en/dev/ref/signals/

Implementar un Signal

Lo primero que debemos de hacer es definir un Signal, para esto empleamos una función que se activa cuando ocurre un evento específico, por ejemplo, la creación de una alerta:

channels/alert/signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Alert

@receiver(post_save, sender=Alert)
def save_user_profile(sender, instance, **kwargs):
    print('Alert Created')

Esta función actuará como receptor de la señal, es decir, se ejecutará cuando se ejecute la señal correspondiente, en este ejemplo, la señal correspondiente es la creación (post_save) de una alerta, mostrará un mensaje por la consola, pero, la tarea a realizar puede ser cualquier otra operación como enviar un correo u otras operaciones en base de datos.

Registrar los Signals

En el archivo apps.py de tu aplicación, debemos de registrar el archivo signals.py en el método ready():

channels/alert/apps.py

from django.apps import AppConfig

class AlertConfig(AppConfig):
    name = 'alert'

    def ready(self):
        import alert.signals

En este método de ejemplo, creamos una alerta:

channels/alert/views.py

from django.contrib.auth.decorators import login_required
from django.http import HttpResponse

from .models import Alert

@login_required
def create(request):
    alert = Alert()
    alert.content = 'Test'
    alert.user = request.user
    alert.save()
    return HttpResponse('Response')

Y creamos la ruta de la vista anterior:

channels/alert/urls.py

urlpatterns = path('dashboard/create',views.create),

Ahora, cada vez que creemos una alerta, se va a ejecutar de manera automática el signal anterior, y esto es un factor importante, cada vez que se cree una alerta, por ejemplo, desde Django Channels, o mediante el consumer que creamos en la sección anterior, se va a ejecutar el signal anterior, como comentamos anteriormente, el signal no es más que una función asociada a un evento salvo que el signal se ejecuta de manera automática al ocurrir el evento.

Documentación oficial:

https://docs.djangoproject.com/en/dev/topics/signals/

https://docs.djangoproject.com/en/dev/ref/signals/

Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy

Acepto recibir anuncios de interes sobre este Blog.