Índice de contenido
- Qué son los Signals en Django
- Tipos Signals
- Model Signals
- Migrations Signals
- Request/Response Signals
- Test Signals
- Database Signals
- El dispatcher de signals
- Receptores (receivers)
- Cómo implementar un Signal en Django paso a paso
- Registrar los Signals
- Ejemplo práctico de Django Signals
- Ejecutar automáticamente el signal
- Buenas prácticas al usar Signals
- Cuándo usar signals y cuándo evitarlos
- Preguntas frecuentes sobre Django Signals
- Conclusión
Django incluye un paquete para manejar las señales o Signals de la aplicación (al igual que el uso de la shell, la Consola Interactiva de Python en Django), 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. 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.
Qué son los Signals en Django
Los signals en Django son eventos que permiten notificar a distintas partes de la aplicación cuando ocurre una acción específica.
Dicho de otra forma, funcionan como mensajeros configurables que informan sobre eventos importantes dentro del sistema.
Por ejemplo:
- crear un usuario
- guardar un modelo
- eliminar un registro
- iniciar una petición HTTP
Cuando ocurre alguno de estos eventos, Django puede disparar una señal que será capturada por una función llamada receiver, la cual ejecutará alguna acción.
Un ejemplo común es enviar un correo electrónico cuando un usuario se registra en la plataforma. En ese caso:
- El usuario se registra.
- Django dispara una señal.
- Un receiver recibe esa señal.
- Se ejecuta una función que envía el correo.
Este mecanismo permite mantener el código desacoplado y organizado, evitando añadir lógica extra directamente en modelos o vistas.
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:
- Para los modelos
- Migraciones
- Peticiones/respuestas
- Pruebas
- 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:
- 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.
- template_rendered: Se envía cuando el sistema de prueba renderiza una plantilla.
Database Signals
Signals relacionado con las conexiones de la base de datos:
- 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/
Cómo funcionan los Django Signals internamente
Para entender mejor cómo funcionan los signals, es importante conocer sus dos componentes principales:
Dispatcher
Receivers
El dispatcher de signals
El dispatcher es el sistema que se encarga de enviar las señales cuando ocurre un evento dentro del framework.
Por ejemplo, cuando un modelo se guarda en la base de datos, Django puede disparar automáticamente el signal:
post_saveEl dispatcher notificará a todos los receptores registrados que estén escuchando ese evento.
Receptores (receivers)
Los receivers son funciones que reaccionan cuando se dispara un signal.
Estas funciones se conectan a las señales utilizando el decorador:
from django.dispatch import receiverUn receiver escucha un tipo específico de signal y normalmente también se limita a un modelo concreto.
Cuando el evento ocurre, Django ejecuta automáticamente la función registrada.
Cómo implementar un Signal en Django paso a paso
Crear un signal en Django es bastante sencillo. Básicamente necesitamos:
- crear un receptor
- conectarlo a un signal
- registrarlo en la aplicación
Crear el archivo signals.py
Primero creamos un archivo llamado:
signals.pydentro de nuestra aplicación.
Por ejemplo:
channels/alert/signals.pyLo 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.signalsEn 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.
Ejemplo práctico de Django Signals
Veamos un ejemplo sencillo para entender cómo funciona todo el flujo.
Crear una alerta cuando se guarda un modelo
Supongamos que tenemos un modelo llamado Alert y queremos ejecutar una acción cada vez que se crea una nueva alerta.
En la vista podríamos tener algo como esto:
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')Cada vez que se ejecuta esta vista, se crea una alerta y se guarda en la base de datos.
Ejecutar automáticamente el signal
Cuando se ejecuta:
alert.save()Django dispara automáticamente el signal:
post_saveEste evento es capturado por nuestro receiver definido en signals.py, que ejecutará la función correspondiente.
Esto significa que el signal se ejecutará sin importar desde dónde se cree el objeto.
Por ejemplo:
- desde una vista
- desde Django Admin
- desde un script
- desde un consumer de Django Channels
Este comportamiento automático es una de las razones por las que los signals son tan útiles para automatizar procesos dentro de una aplicación.
Buenas prácticas al usar Signals
Aunque los signals son muy útiles, es importante utilizarlos correctamente.
Algunas buenas prácticas son:
- Mantener los signals simples
- Los receivers deberían ejecutar lógica pequeña y específica.
- Si la lógica es compleja, es mejor delegarla a un servicio o función externa.
- Evitar dependencias ocultas
- Uno de los problemas de los signals es que pueden crear comportamientos que no son obvios para otros desarrolladores.
- Por eso es recomendable documentarlos bien.
- Evitar lógica crítica en signals
- No es recomendable usar signals para operaciones críticas del sistema, ya que pueden ejecutarse en momentos inesperados.
Cuándo usar signals y cuándo evitarlos
Los signals son útiles cuando queremos reaccionar a eventos sin modificar directamente el código que los genera.
Son ideales para:
- enviar notificaciones
- registrar logs
- actualizar modelos relacionados
- disparar tareas asíncronas
Sin embargo, no siempre son la mejor opción.
Conviene evitarlos cuando:
- la lógica forma parte del flujo principal
- el comportamiento debe ser explícito
- el sistema puede volverse difícil de mantener
Preguntas frecuentes sobre Django Signals
- ¿Qué son los signals en Django?
- Son un sistema de eventos que permite ejecutar funciones automáticamente cuando ocurre una acción dentro de la aplicación.
- ¿Dónde se registran los signals en Django?
- Normalmente se definen en un archivo signals.py y se registran en apps.py dentro del método ready().
- ¿Cuál es el signal más utilizado?
- Uno de los más comunes es post_save, que se ejecuta después de guardar un modelo.
- ¿Puedo crear signals personalizados?
- Sí. Django permite crear signals personalizados utilizando el módulo django.dispatch.
Documentación oficial:
Conclusión
Los Signals en Django son una herramienta poderosa para construir aplicaciones desacopladas y automatizar tareas internas del sistema.
Permiten reaccionar a eventos importantes dentro de la aplicación sin modificar directamente el código que los genera, lo que ayuda a mantener una arquitectura más limpia y modular.
Bien utilizados, los signals pueden simplificar muchas tareas comunes como enviar notificaciones, registrar eventos o ejecutar acciones posteriores al guardado de modelos.
Sin embargo, también es importante utilizarlos con moderación y aplicar buenas prácticas para evitar comportamientos ocultos que puedan dificultar el mantenimiento del proyecto.
https://docs.djangoproject.com/en/dev/topics/signals/
https://docs.djangoproject.com/en/dev/ref/signals/
Siguiente paso, aprende a crear una Rest API en Django (con Django Rest Framework)