Django signals

Referencias


Para un pequeño ejemplo, vamos a crear un modelo UserProfile con la información del usuario. Vamos a añadir los campos pais y provincia y un campo user que tendrá una relación OneToOneField con settings.AUTH_USER_MODEL.

En este caso, se supone que se usara después de que el usuario haya sido creado, pero no la mostrara en el formulario de registro, por eso, los campos pais y provincia serán default='', blank=True (blank=True, ya va a gustos si cuando muestre el formulario, es requerido o no).

# accounts/models.py
from django.db import models
from django.conf import settings


class UserProfile(models.Model):
    user = models.OneToOneField(
        settings.AUTH_USER_MODEL, primary_key=True, related_name='user_profile'
    )
    pais = models.CharField(max_length=100, default='', blank=True)
    provincia = models.CharField(max_length=100, default='', blank=True)
    # Otros campos...

Ahora, podemos hacelo de dos maneras, una añadiendo el signal en el mismo modulo del modelo, o bien creando un modulo separado signals.py.

Para crearlo en el mismo modulo models.py, creamos el signal abajo del archivo.

# accounts/models.py
# Importar los módulos necesarios al principio.
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings


@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_handler(sender, instance, created, **kwargs):
    if not created:
        return
    UserProfile.objects.create(user=instance)

Cada vez que se cree, un usuario, se creara un campo en el modelo UserProfile. Esta es la manera rápido, pero si hay muchos signals lo ideal es ponerlos todos juntos en el modulo signals.

# accounts/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.conf import settings

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_handler(sender, instance, created, **kwargs):
    if not created:
        return
    UserProfile.objects.create(user=instance)

De momento, no hemos hecho nada nuevo…, creamos un modulo apps.py y añadimos.

# accounts/apps.py
from django.apps import AppConfig


class AccountsConfig(AppConfig):
    name = 'accounts'
    verbose_name = 'Accounts Application'

    def ready(self):
        from . import signals

Donde name = 'accounts' es la ruta a la app, si estuviera en apps/accounts, se tendria que cambiar por name = 'apps.accounts', verbose_name es un nombre legible que le damos.

Con esto, cada vez que se cree un nuevo usuario en la base de datos, se creara una fila en la table accounts_userprofile con un campo relacional a auth_user (por defecto).