Django innehåller en ”signal dispatcher” som hjälper frikopplade applikationer att få meddelanden när åtgärder inträffar någon annanstans i ramverket. I ett nötskal tillåter signaler vissa avsändare att meddela en uppsättning mottagare att någon åtgärd har ägt rum. De är särskilt användbara när många kodstycken kan vara intresserade av samma händelser.
En tredjepartsapp kan t.ex. registrera sig för att få meddelanden om ändringar i inställningarna:
from django.apps import AppConfig
from django.core.signals import setting_changed
def my_receiver(sender, **kwargs):
print("Setting changed!")
class MyAppConfig(AppConfig):
...
def ready(self):
setting_changed.connect(my_receiver)
Djangos inbyggda signaler låter användarkoden få meddelande om vissa åtgärder.
Du kan också definiera och skicka dina egna anpassade signaler. Se definiera-och-sända-signaler nedan.
Varning
Signaler ger sken av lös koppling, men de kan snabbt leda till kod som är svår att förstå, justera och felsöka.
Om möjligt bör du välja att anropa hanteringskoden direkt i stället för att skicka den via en signal.
För att ta emot en signal registrerar du en mottagarfunktion med metoden Signal.connect(). Mottagarfunktionen anropas när signalen skickas. Alla signalens mottagarfunktioner anropas en i taget, i den ordning de registrerades.
receiver – Den callback-funktion som kommer att anslutas till denna signal. Se Mottagarens funktioner för mer information.
sender – Anger en viss avsändare att ta emot signaler från. Se Anslutning till signaler som skickas av specifika avsändare för mer information.
weak – Django stores signal receivers as weak references by
default. Thus, if your receiver is a local function, it may be
garbage collected. To prevent this, pass weak=False when you call
the signal’s connect() method.
dispatch_uid – En unik identifierare för en signalmottagare i de fall där dubbla signaler kan skickas. Se Förhindra dubblerade signaler för mer information.
Låt oss se hur detta fungerar genom att registrera en signal som anropas efter varje HTTP-begäran är klar. Vi kommer att ansluta till request_finished-signalen.
Först måste vi definiera en mottagarfunktion. En mottagare kan vara vilken Python-funktion eller metod som helst:
def my_receiver(sender, **kwargs):
print("Request finished!")
Notice that the function takes a sender argument, along with wildcard
keyword arguments (**kwargs); all signal receivers must take these
arguments.
We’ll look at senders a bit later, but
right now look at the **kwargs argument. All signals send keyword
arguments, and may change those keyword arguments at any time. In the case of
request_finished, it’s documented as sending no
arguments, which means we might be tempted to write our signal handling as
my_receiver(sender).
Detta skulle vara fel - i själva verket kommer Django att kasta ett fel om du gör det. Det beror på att argument när som helst kan läggas till i signalen och din mottagare måste kunna hantera dessa nya argument.
Mottagare kan också vara asynkrona funktioner, med samma signatur men deklarerade med async def:
async def my_receiver(sender, **kwargs):
await asyncio.sleep(5)
print("Request finished!")
Signaler kan skickas antingen synkront eller asynkront och mottagarna kommer automatiskt att anpassas till rätt anropsstil. Se Skicka signaler för mer information.
Det finns två sätt att ansluta en mottagare till en signal. Du kan välja den manuella anslutningsvägen:
from django.core.signals import request_finished
request_finished.connect(my_receiver)
Alternativt kan du använda en receiver()-dekorator:
signal – En signal eller en lista med signaler att ansluta en funktion till.
kwargs – Argument med nyckelord med jokertecken att skicka till en funktion.
Så här kommer du i kontakt med inredaren:
from django.core.signals import request_finished
from django.dispatch import receiver
@receiver(request_finished)
def my_receiver(sender, **kwargs):
print("Request finished!")
Now, our my_receiver function will be called each time a request finishes.
Var ska den här koden finnas?
I strikt mening kan signalhanterings- och registreringskoden placeras var som helst, även om det rekommenderas att undvika applikationens rotmodul och dess models-modul för att minimera bieffekterna av importerad kod.
In practice, signal receivers are usually defined in a signals
submodule of the application they relate to. Signal receivers are
connected in the ready() method of your
application configuration class. If
you’re using the receiver() decorator, import the signals
submodule inside ready(), this will implicitly
connect signal receivers:
from django.apps import AppConfig
from django.core.signals import request_finished
class MyAppConfig(AppConfig):
...
def ready(self):
# Implicitly connect signal receivers decorated with @receiver.
from . import signals
# Explicitly connect a signal handler.
request_finished.connect(signals.my_receiver)
Observera
The ready() method may be executed more than
once during testing, so you may want to guard your signals from
duplication if your receiver is a bound
method on an instance that may be recreated.
Vissa signaler skickas många gånger, men du kommer bara att vara intresserad av att ta emot en viss delmängd av dessa signaler. Tänk till exempel på django.db.models.signals.pre_save-signalen som skickas innan en modell sparas. För det mesta behöver du inte veta när någon modell sparas - bara när en specifik modell sparas.
I dessa fall kan du registrera dig för att ta emot signaler som endast skickas av vissa avsändare. I fallet med django.db.models.signals.pre_save kommer avsändaren att vara den modellklass som sparas, så du kan ange att du bara vill ha signaler som skickas av vissa modeller:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from myapp.models import MyModel
@receiver(pre_save, sender=MyModel)
def my_handler(sender, **kwargs): ...
Funktionen my_handler anropas endast när en instans av MyModel sparas.
Olika signaler använder olika objekt som sina avsändare; du måste konsultera inbyggd signaldokumentation för detaljer om varje enskild signal.
When dispatch_uid is not provided, Django identifies each receiver using
its Python object identity and registers it only once. For module-level
functions, static methods, and class methods, the identity is stable, so
connecting the same receiver more than once has no effect:
def my_handler(sender, **kwargs): ...
my_signal.connect(my_handler) # Running this code again is a no-op.
Bound methods, which take a self argument, are different. Their identity
is tied to the specific instance, so connecting the same method from a new
instance registers it as an additional receiver:
def connect_signals():
backend = Backend()
my_signal.connect(backend.my_handler) # A distinct receiver.
connect_signals() # Running this code again registers another receiver.
When using a bound method as a receiver, multiple registrations can be
prevented by supplying a unique dispatch_uid. This identifier will usually
be a string, although any hashable object will suffice. The receiver will only
be bound to the signal once for each unique dispatch_uid value:
from django.core.signals import request_finished
request_finished.connect(my_receiver, dispatch_uid="my_unique_identifier")
Dina applikationer kan dra nytta av signalinfrastrukturen och tillhandahålla sina egna signaler.
När ska man använda anpassade signaler
Signaler är implicita funktionsanrop som gör felsökningen svårare. Om sändaren och mottagaren av din anpassade signal båda finns inom ditt projekt är det bättre att använda ett explicit funktionsanrop.
Alla signaler är django.dispatch.Signal-instanser.
Till exempel:
import django.dispatch
pizza_done = django.dispatch.Signal()
Detta deklarerar en pizza_done signal.
Det finns två sätt att skicka signaler synkront i Django.
Signaler kan också skickas asynkront.
För att skicka en signal anropar du antingen Signal.send(), Signal.send_robust(), await Signal.asend() eller await Signal.asend_robust(). Du måste ange argumentet sender (som oftast är en klass) och kan ange så många andra nyckelordsargument som du vill.
Så här kan det till exempel se ut när vi skickar vår signal pizza_done:
class PizzaStore:
...
def send_pizza(self, toppings, size):
pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
...
Alla fyra metoderna returnerar en lista med tupelpar [(receiver, response), ...], som representerar listan över anropade mottagarfunktioner och deras svarsvärden.
send() skiljer sig från send_robust() i hur undantag som skapas av mottagarfunktioner hanteras. send() fångar inte upp några undantag som tas upp av mottagare; den tillåter helt enkelt att fel sprids. Därför kan det hända att inte alla mottagare får meddelande om en signal när det uppstår ett fel.
send_robust() fångar upp alla fel som härrör från Pythons klass Exception och ser till att alla mottagare meddelas om signalen. Om ett fel inträffar returneras felinstansen i tuple-paret för den mottagare som orsakade felet.
Spårningarna finns i attributet __traceback__ i de fel som returneras när man anropar end_robust().
asend() liknar send(), men det är en coroutine som måste inväntas:
async def asend_pizza(self, toppings, size):
await pizza_done.asend(sender=self.__class__, toppings=toppings, size=size)
...
Whether synchronous or asynchronous, receivers will be correctly adapted to
whether send() or asend() is used. Synchronous receivers will be
called using sync_to_async() when invoked via asend(). Asynchronous
receivers will be called using async_to_sync() when invoked via
send(). Similar to the case for middleware,
there is a small performance cost to adapting receivers in this way. Note that
in order to reduce the number of sync/async calling-style switches within a
send() or asend() call, the receivers are grouped by whether or not
they are async before being called. This means that an asynchronous receiver
registered before a synchronous receiver may be executed after the synchronous
receiver. In addition, async receivers are executed concurrently using
asyncio.TaskGroup.
Alla inbyggda signaler, utom de som ingår i den asynkrona request-response-cykeln, skickas med Signal.send().
In older versions, async receivers were executed via asyncio.gather().
För att koppla bort en mottagare från en signal, anropa Signal.disconnect(). Argumenten är de som beskrivs i Signal.connect(). Metoden returnerar True om en mottagare har kopplats bort och False om så inte är fallet. När sender skickas som en latent referens till <app label>.<model>, returnerar denna metod alltid None.
Argumentet receiver anger den registrerade mottagare som ska kopplas bort. Det kan vara None om dispatch_uid används för att identifiera mottagaren.
aug. 05, 2026