Sinais (Signals)¶
O Django incluí um “dispachador de sinal” que ajuda ao permitir que aplicações dissociadas sejam notificadas quando uma ação ocorre em qualquer lugar do framework. Em resumo, sinais permitem certos remetentes notificar um conjunto de receptores sobre alguma ação que tenha ocorrido. Eles são especialmente úteis quando muitas peças de código podem estar interessados nos mesmos eventos.
O Django fornece um conjunto de sinais embutidos que deixam o código do usuário ser notificado pelo próprio Django sobre certas ações. Estas incluem algumas notificações úteis:
django.db.models.signals.pre_save
&django.db.models.signals.post_save
Enviado antes ou depois que um método de model
save()
é chamado.django.db.models.signals.pre_delete
&django.db.models.signals.post_delete
Enviado antes ou depois que um método de model
delete()
é chamado.django.core.signals.request_started
&django.core.signals.request_finished
Enviado quando o Django inicia ou finaliza uma requisição HTTP.
Veja a documentação de sinais embutidos para uma lista completa, e uma explicação completa de cada sinal.
Você também pode definir e enviar seus próprios sinais; veja abaixo.
Ouvindo sinais¶
Para receber um sinal, você precisa registrar uma função receptora que será
chamada quando o sinal é enviado. Vamos ver como isto funciona registrando um
sinal que é chamado depois de cada requisição HTTP é finalizada. Nós
conectaremo-nos ao sinal request_finished
.
Funções receptoras¶
Primeiro, nós precisamos definir uma função receptora. Um receptor pode ser qualquer função Python ou método:
def my_callback(sender, **kwargs):
print "Request finished!"
Observe que a função recebe um argumento sender
, junto com o argumento
coringa (**kwargs
); todo manipulador de sinal recebe estes argumentos.
Nós olharemos o remetente um pouco depois, mas agora olhe o argumento
**kwargs
. Todos os sinais enviam argumentos nomeados, e podem mudar seus
argumentos nomeados a qualquer momento. Neste caso o
request_finished
, ele está documentado como se não
enviasse argumentos, que significa que poderiámos ser tentados a escrever nosso
manipulador do sinal como my_callback(sender)
.
Isso poderia estar errado – de fato, o Django irá lançar um erro se você fizer isso. Isto porque, em qualquer ponto, argumentos poderiam ser adicionados ao sinal, e o receptor deve ser capaz de manipular estes argumentos.
Conectando funções receptoras¶
Agora, nós precisaremos conectar nosso receptor ao sinal:
from django.core.signals import request_finished
request_finished.connect(my_callback)
Agora, nossa função my_callback
será chamada a cada vez que uma requisição
for finalizada.
Onde este código deve ficar?
Você poder colocar o código manipulador e de registro de sinal aonde você
quiser. Entretanto, você precisará assegurar-se de que o módulo já tenha
sido importado anteriormente, para que este manipulador de sinal seja
registrado antes que qualquer sinal seja enviado. Isto faz do models.py
de sua aplicação, um bom lugar para colocar o regsitro de manipuladores de
sinais.
Conectando-se a sinais enviados por remetentes específicos¶
Alguns sinais são enviados muitas vezes, mas você somente é interessado em
receber um certo sub-conjunto destes sinais. Por exemplo, considere o sinal
django.db.models.signals.pre_save
enviado antes de um model ser salvo.
Na maioria das vezes, você não precisa saber quando qualquer model foi
salvo – só quando um model específico é salvo.
Nestes casos, você pode registrá-lo para receber sinais enviados somente por um
remetente em particular. No caso do django.db.models.signals.pre_save
, o
remetente será a classe model que estiver sendo salva, então você pode indicar
que você somente quer sinais enviados por algum model:
from django.db.models.signals import pre_save
from myapp.models import MyModel
def my_handler(sender, **kwargs):
...
pre_save.connect(my_handler, sender=MyModel)
A função my_handler
somente será chamada quando uma instância de MyModel
for salva.
Sinais diferentes usam objetos diferentes como seus remetentes; você precisará consultar a documentação de sinais embutidos para detalhes de cada sinal em particular.
Definindo e enviando sinais¶
Sua aplicação pode tirar proveito da infraestrutura de sinais e prover seus próprios sinais.
Definindo sinais¶
-
class
Signal
([providing_args=list])¶
Todos os sinais são instâncias de django.dispatch.Signal
. O
providing_args
é uma lista de nomes de argumentos que o sinal fornecerá aos
ouvintes.
Por exemplo:
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])
Este declara um sinal pizza_done
que fornecerá aos receptores os argumentos
toppings
e size
.
Lembre-se de que você está autorizado a alterar esta lista de argumentos a qualquer momento, então obter o direito de API, na primeira tentativa, não é necessário.
Enviando sinais¶
-
Signal.
send
(sender, **kwargs)¶
Para enviar um sinal, chame Signal.send()
. Você deve prover o argumento
sender
, e pode fornecer muitos outros argumentos nomeados conforme sua
vontade.
Por exemplo, aqui mostramos como nosso envio de sinal pizza_done
, pode
ficar:
class PizzaStore(object):
...
def send_pizza(self, toppings, size):
pizza_done.send(sender=self, toppings=toppings, size=size)
...