Segnali (Signals)
I segnali (signals) di Django permettono a componenti disaccoppiati dell’applicazione di comunicare tra loro. Quando si verifica un determinato evento, come il salvataggio di un modello o l’arrivo di una richiesta HTTP, Django invia un segnale che può essere intercettato da uno o più ricevitori (receivers). Questo meccanismo è fondamentale per mantenere il codice modulare e pulito.
Come Funzionano i Segnali
Django segue il pattern observer: un mittente (sender) emette un segnale, e tutti i ricevitori registrati per quel segnale vengono eseguiti automaticamente. Il framework mette a disposizione diversi segnali predefiniti.
Segnali dei Modelli
I segnali più utilizzati riguardano le operazioni sui modelli:
from django.db.models.signals import pre_save, post_save, pre_delete, post_delete
from django.dispatch import receiver
from .models import Articolo
@receiver(pre_save, sender=Articolo)
def prima_del_salvataggio(sender, instance, **kwargs):
"""Eseguito prima del salvataggio di un Articolo."""
if not instance.slug:
instance.slug = instance.titolo.lower().replace(" ", "-")
@receiver(post_save, sender=Articolo)
def dopo_il_salvataggio(sender, instance, created, **kwargs):
"""Eseguito dopo il salvataggio di un Articolo."""
if created:
print(f"Nuovo articolo creato: {instance.titolo}")
else:
print(f"Articolo aggiornato: {instance.titolo}")
I segnali pre_delete e post_delete funzionano in modo analogo per le operazioni di eliminazione:
@receiver(pre_delete, sender=Articolo)
def prima_della_cancellazione(sender, instance, **kwargs):
"""Eseguito prima dell'eliminazione di un Articolo."""
print(f"Sto per eliminare: {instance.titolo}")
@receiver(post_delete, sender=Articolo)
def dopo_la_cancellazione(sender, instance, **kwargs):
"""Eseguito dopo l'eliminazione di un Articolo."""
# Elimina file associati, ad esempio
if instance.immagine:
instance.immagine.delete(save=False)
Segnale m2m_changed
Il segnale m2m_changed viene emesso quando si modificano relazioni many-to-many:
from django.db.models.signals import m2m_changed
@receiver(m2m_changed, sender=Articolo.tags.through)
def tags_modificati(sender, instance, action, **kwargs):
if action == "post_add":
print(f"Tag aggiunti all'articolo: {instance.titolo}")
elif action == "post_remove":
print(f"Tag rimossi dall'articolo: {instance.titolo}")
Segnali delle Richieste HTTP
Django offre segnali legati al ciclo di vita delle richieste:
from django.core.signals import request_started, request_finished
@receiver(request_started)
def richiesta_iniziata(sender, environ, **kwargs):
print("Una nuova richiesta HTTP è arrivata")
@receiver(request_finished)
def richiesta_terminata(sender, **kwargs):
print("La richiesta HTTP è stata completata")
Connessione Manuale con Signal.connect()
Oltre al decoratore @receiver, puoi connettere i segnali manualmente usando il metodo connect():
def gestisci_salvataggio(sender, instance, **kwargs):
print(f"Modello salvato: {instance}")
post_save.connect(gestisci_salvataggio, sender=Articolo)
Creare Segnali Personalizzati
Puoi definire segnali personalizzati per eventi specifici della tua applicazione:
from django.dispatch import Signal
# Definizione del segnale personalizzato
ordine_completato = Signal()
# Emissione del segnale
def completa_ordine(ordine):
ordine.stato = "completato"
ordine.save()
ordine_completato.send(sender=ordine.__class__, ordine=ordine)
# Ricezione del segnale
@receiver(ordine_completato)
def invia_conferma_ordine(sender, ordine, **kwargs):
print(f"Invio email di conferma per ordine #{ordine.id}")
Registrazione nei File apps.py
La pratica consigliata in Django 5.x è registrare i segnali nel metodo ready() della configurazione dell’app:
# myapp/apps.py
from django.apps import AppConfig
class MyappConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "myapp"
def ready(self):
import myapp.signals # Importa il modulo con i receiver
Conclusione
I segnali di Django sono uno strumento potente per disaccoppiare la logica dell’applicazione. Permettono di reagire automaticamente a eventi come salvataggio, eliminazione e modifiche ai modelli senza dover modificare il codice originale. Usa i segnali con moderazione: per logica strettamente legata al modello, considera l’override dei metodi save() e delete() come alternativa più esplicita.