💻
Dicas de Django
  • Dica 1 - Django boilerplate e cookiecutter-django
  • Dica 1.1 - Django boilerplate
  • Dica 2 - Django extensions
  • Dica 3 - Django bulk_create e django-autoslug
  • Dica 4 - Django Admin personalizado
  • Dica 5 - Django Admin Date Range filter
  • Dica 6 - Geradores de senhas randômicas - uuid, hashids, secrets
  • Dica 7 - Rodando o ORM do Django no Jupyter Notebook
  • Dica 8 - Conhecendo o Django Debug Toolbar
  • Dica 9 - Escondendo suas senhas python-decouple
  • Dica 10 - Prototipagem de web design (Mockup)
  • Dica 11 - Bootstrap e Bulma + Colorlib
  • Dica 12 - Imagens: pexels e unsplash
  • Dica 13 - Cores
  • Dica 14 - Herança de Templates e Arquivos estáticos
  • Dica 15 - Busca por data no frontend
  • Dica 16 - Filtros com django-filter
  • Dica 17 - Criando comandos personalizados
  • Dica 18 - bulk_create e bulk_update
  • Dica 19 - Criando Issues por linha de comando com a api do github
  • Dica 20 - api github e click
  • Dica 21 - Criando issues por linha de comando com gitlab cli
  • 022-criando-issues-por-linha-de-comando-com-bitbucket-cli
  • Dica 23 - Diferença entre JSON dump, dumps, load e loads
  • Dica 24 - Barra de progresso
  • Dica 25 - Rodando Shell script dentro do Python
  • Dica 26 - Rodando Python dentro do Shell script
  • Dica 27 - Retornando os nomes dos campos do model
  • Dica 28 - Admin: Usando short description
  • Dica 29 - Django Admin: Criando actions no Admin
  • Dica 30 - Django Admin: Editando direto na listview do Admin
  • Dica 31 - Django Admin: Pegando usuário logado no Admin
  • Dica 32 - Django Admin: Sobreescrevendo os templates do Admin
  • Dica 33 - Github cli
  • Dica 34 - Django: custom template tags
  • Dica 35 - Django: passando usuário logado no formulário
  • Dica 36 - Django: visualizando seus modelos com graph models
  • Dica 37 - Faker
  • Dica 38 - Django: Paginação + Filtros
  • Dica 39 - Django Admin: display decorator (Django 3.2+)
  • Dica 40 - Formulários: date, datetime, duration e templatetags de data
  • Dica 41 - django-seed
  • Dica 42 - Custom context processors
  • Dica 43 - django-admin-rangefilter
  • Dica 44 - Django: F() expression
  • Dica 45 - DRF: Scaffold django apis - Django REST framework
  • Dica 46 - DRF: drf-yasg - Yet another Swagger generator
  • Dica 47 - DRF: djoser - Django REST framework
  • Dica 48 - DRF: Reset de Senha com djoser - Django REST framework
  • Dica 49 - DRF: Autenticação via JWT com djoser - Django REST framework
  • Dica 50 - DRF: Django CORS headers
  • Dica 51 - DRF: paginação
  • Dica 52 - DRF: django-filter
  • Dica 53 - DRF: Criando subrota com action
  • 54-django-extensions-mais-comandos
  • Dica 55 - Rodando Django em https localmente com runserver_plus
  • Dica 56 - Django inlineformset_factory + HTMX
  • Dica 57 - Criando API com Django SEM DRF
  • Dica 58 - Rodando PostgreSQL com Docker + Portainer + pgAdmin + Django local para desenvolvimento
  • Dica 59 - Django: Busca por palavras acentuadas ou sem acento
  • Dica 60 - Django: Adicionando atributos extras no formulário
  • Dica 01 - Criando Issues com API do Github (Linux)
  • Dica 02 - Usando http.server
  • Dica 03 - Criando um template com Bulma CSS
  • Dica 04 - Criando um template com Tailwind CSS
  • Dica 05 - htmx simples
  • Dica 06 - Criando o projeto Django
  • Dica 07 - PostgreSQL, pgAdmin e MailHog com docker-compose
  • Dica 08 - Aplicando isort e autopep8
  • Dica 09 - Aplicando djhtml
  • Dica 10 - Criando Makefile
  • Dica 11 - Criando Landpage de produtos
  • 072-012-fale-co-nosco-form-email
  • Dica 13 - Dashboard com Django e Tailwind CSS
  • Dica 14 - Django Custom User com e-mail
  • Dica 15 - Login com e-mail no Django
  • Dica 16 - Logout
  • Dica 17 - Cadastro de Usuários no Django
  • Dica 18 - Esqueci a senha
  • Dica 19.1 - Modelagem - OneToMany - Um pra Muitos - ForeignKey - Chave Estrangeira
  • Dica 19.2 - Modelagem - OneToOne - Um pra Um
  • Dica 19.3 - Modelagem - ManyToMany - Muitos pra Muitos
  • Dica 19.4 - Modelagem - Abstract Inheritance - Herança Abstrata
  • Dica 19.5 - Modelagem - Multi-table Inheritance - Herança Multi-tabela
  • Dica 19.6 - Modelagem - Proxy Model
  • Dica 19.7 - Modelagem - Resumo
  • Dica 20 - Templates
  • Dica 21 - Tentativas de Login
  • Dica 22 - Validação
  • Dica 23 - CRUD de produtos
  • Dica 24 - Alpine.js e Django
  • 091-25-dica-queryset
  • Dica 26 - Paginação e Breadcrumb
  • Dica 27 - Signals
  • Dica 28 - Gerando dados aleatórios com Faker - faker-commerce
  • Dica 29 - Importando CSV
  • 096-30-import-csv-inmemoryuploadedfile
  • Dica 31 - Importando CSV com Pandas
  • Dica 32 - Importando CSV com Dask
  • Dica 33 - Importando XLSX com OpenPyXL
  • 100-34-export-csv
  • Dica 35 - Exportando XLSX mais rápido com pyexcelerate
  • Dica 36 - Exportando CSV e XLSX pelo front no projeto
  • Novidades do Django 5.1
  • Django Router
  • 105-django-52
Powered by GitBook
On this page
  • Problema
  • O que é um Signal?
  • Exemplos
  • Model Profile
  • Detalhando um pouco mais
  • Model Product
  • Bonus: colocando o Signals num arquivo separado

Was this helpful?

Dica 27 - Signals

PreviousDica 26 - Paginação e BreadcrumbNextDica 28 - Gerando dados aleatórios com Faker - faker-commerce

Last updated 2 years ago

Was this helpful?

Doc:

Problema

Suponha que você queira enviar um e-mail de boas-vindas para um novo usuário.

Onde você faria isso? Na views?

E se você usasse mais views para fazer esse cadastro?

Você criaria uma função! Hum... pode ser.

Mas e se você cadastra-se um usuário pelo Admin?

Outra situação:

Suponha que você não tenha acesso ao model User.

Neste projeto nós temos acesso, mas no Django padrão nós não teríamos acesso.

Como você faria para, tanto na views, como no Admin, e até no shell do Django, saber se um model do User foi criado ou modificado?

Para isso nós temos o signals.

O que é um Signal?

No Django, os "signals" são uma forma de enviar sinais ou notificações quando ocorre uma determinada ação no banco de dados ou em algum modelo específico. Esses sinais podem ser usados para executar ações adicionais ou enviar notificações quando determinadas mudanças ocorrem no modelo.

Toda vez que um model é criado, ou alterado, é enviado um sinal para a aplicação. E este sinal pode fazer alguma coisa.

Exemplos

  • Ao criar um novo usuário, criar um Profile pra ele.

  • Ao criar um novo usuário, enviar um e-mail pra ele.

  • Ao criar um novo produto, definir um slug automaticamente.

Model Profile

Considere o model Profile.

class Profile(models.Model):
    user = models.OneToOneField(
        User,
        on_delete=models.PROTECT,
        verbose_name='usuário'
    )
    birthday = models.DateField('data de nascimento', null=True, blank=True)
    linkedin = models.URLField(null=True, blank=True)
    rg = models.CharField(max_length=10, null=True, blank=True)
    cpf = models.CharField(max_length=11, null=True, blank=True)

Agora vamos considerar o seguinte:

Toda vez que eu criar um novo usuário, eu quero automaticamente criar um Profile pra ele.

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


@receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
    instance.profile.save()

Detalhando um pouco mais

No terminal digite

python manage.py shell_plus

Depois

from django.contrib.auth import get_user_model

User = get_user_model()

User  # aqui nós vemos que o nosso User está em backend.accounts.models.User

Exemplo 1

Se fizermos

instance = User.objects.create()

Podemos ter os signals pre_save e post_save.

A diferença é que o pre_save tem o instance, e o post_save tem o instance e o created.

# pre_save -> instance
instance = User.objects.create()
# post_save -> instance, created=True

Note também que no pre_save você ainda não tem o id do objeto.

Exemplo 2

Neste outro exemplo, usando o comando save()

# pre_save -> instance
instance.save()
# post_save -> instance, created=False

A diferença aqui é que em post_save o created=False.

Exemplo 3

Ao deletar temos os signals pre_delete e post_delete.

Exemplo 4

Agora vamos ao código

# accounts/models.py

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

def user_created_handler(*args, **kwargs):
    print('Usuário criado com sucesso.')

post_save.connect(user_created_handler, sender=User)

Ou podemos usar o decorator receiver.

@receiver(post_save, sender=User)
def user_created_handler(*args, **kwargs):
    print('Usuário criado com sucesso.')
    print(args, kwargs)

Quando adicionarmos um novo usuário...

from django.contrib.auth import get_user_model

User = get_user_model()

User.objects.create_user(email='user01@email.com')

() {'signal': <django.db.models.signals.ModelSignal object at 0x7fa6a116b490>, 'sender': <class 'backend.accounts.models.User'>, 'instance': <User: user01@email.com>, 'created': True, 'update_fields': None, 'raw': False, 'using': 'default'}

Veja o

'instance': <User: user01@email.com>, 'created': True

Exemplo 5

Podemos acrescentar mais parâmetros como

@receiver(post_save, sender=User)
def user_created_handler(sender, instance, created, *args, **kwargs):
    print('Usuário criado com sucesso.')
    # print(args, kwargs)
    if created:
        print('Envia e-mail para', instance.email)
    else:
        print(instance.email, 'foi salvo.')

Salve alguns usuários no Admin e veja o resultado no terminal.

Exemplo 6

Agora veremos o pre_save.

@receiver(pre_save, sender=User)
def user_pre_save_handler(sender, instance, *args, **kwargs):
    print(instance.email, instance.id)  # None
    # NÃO FAÇA ISSO -> instance.save()  # Loop infinito

Teste pelo Admin.

Exemplo 7 - Profile

Agora já conseguimos entender o signal do Profile.

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


@receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
    instance.profile.save()

Exemplo 8 - Envio de e-mail

# accounts/models.py
@receiver(post_save, sender=User)
def send_email_on_user_creation(sender, instance, created, **kwargs):
    if created:
        send_mail(
            'New user created',
            f'A new user with email {instance.email} has been created.',
            'from@example.com',
            ['to@example.com'],
            fail_silently=False,
        )

Model Product

Em Product vamos adicionar um slug.

# product/models.py
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils.text import slugify


class Product(TimeStampedModel):
    ...
    slug = models.SlugField(blank=True, null=True)


@receiver(pre_save, sender=Product)
def product_pre_save(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = slugify(instance.title)

Bonus: colocando o Signals num arquivo separado

touch backend/product/signals.py
# product/signals.py
from django.utils.text import slugify


def product_pre_save(sender, instance, *args, **kwargs):
    if not instance.slug:
        instance.slug = slugify(instance.title)

Agora precisamos editar o arquivo apps.py.

# product/apps.py
class ProductConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'myproject.product'

    def ready(self):
        from django.db.models.signals import pre_save

        from .models import Product
        from .signals import product_pre_save

        pre_save.connect(product_pre_save, sender=Product)

Para finalizar vamos colocar o slug como read_only no Admin.

# product/admin.py

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    ...
    list_display = ('__str__', 'slug', 'category')
    readonly_fields = ('slug',)
    ...
https://docs.djangoproject.com/en/4.1/topics/signals/
https://docs.djangoproject.com/en/4.1/ref/signals/