---
title: "Signaux"
version: 6.1
locale: fr
source: https://docs.djangoproject.com/fr/6.1/topics/signals/
canonical: https://djangodocs.dev/fr/6.1/topics/signals/
---
# Signaux

Django contient un « distributeur de signaux » qui permet aux applications découplées de pouvoir plus facilement être averties quand des actions se produisent ailleurs dans un projet. En résumé, les signaux permettent à certains *expéditeurs* d’avertir un ensemble de *destinataires* qu’une action a eu lieu. Ils sont particulièrement utiles lorsque beaucoup de parties de code peuvent être intéressées aux mêmes événements.

Par exemple, une application tierce peut s’inscrire pour être avertie des modifications de réglages

```
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)
```

Les [signaux propres à Django](/fr/6.1/ref/signals/) permettent à du code utilisateur d’être averti de certaines actions.

Vous pouvez également définir et envoyer vos propres signaux personnalisés. Voir [Définition et envoi de signaux](#defining-and-sending-signals) ci-dessous.

> **Warning**
>
> Les signaux donnent une apparence de couplage faible, mais ils peuvent rapidement amener à du code difficile à comprendre, à ajuster et à déboguer.
>
> Partout où c’est possible, vous devriez choisir des appels directs au code à exécuter, plutôt que par la distribution de signaux.

## Écoute de signaux

Pour recevoir un signal, inscrivez une fonction *réceptrice* en utilisant la méthode [`Signal.connect()`](#django.dispatch.Signal.connect). Cette fonction sera appelée au moment où le signal est envoyé. Toutes les fonctions réceptrices d’un signal sont appelées consécutivement dans l’ordre où elles ont été inscrites.

#### `Signal.connect(receiver, sender=None, weak=True, dispatch_uid=None)`

**Paramètres:** - `receiver` – La fonction réceptrice qui sera connectée à ce signal. Voir [Fonctions réceptrices](#receiver-functions) pour plus d’informations.
- `sender` – Indique un expéditeur particulier duquel recevoir les signaux. Voir [Connexion aux signaux envoyés par des expéditeurs spécifiques](#connecting-to-specific-signals) pour plus d’informations.
- `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` – Un identifiant unique pour un récepteur de signal afin d’éviter que certains signaux puissent être envoyés à double. Voir [Prévention des signaux dupliqués](#preventing-duplicate-signals) pour plus d’informations.

Voyons comment ça fonctionne en inscrivant un signal qui sera appelé à la fin de chaque requête HTTP. Nous allons nous connecter au signal [`request_finished`](/fr/6.1/ref/signals/#django.core.signals.request_finished).

### Fonctions réceptrices

Tout d’abord, nous devons définir une fonction réceptrice. Celle-ci peut être n’importe quelle fonction ou méthode Python :

```
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](#connecting-to-specific-signals), 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`](/fr/6.1/ref/signals/#django.core.signals.request_finished), it’s documented as sending no
arguments, which means we might be tempted to write our signal handling as
`my_receiver(sender)`.

Ce serait une erreur. En fait, Django génère une exception dans ce cas, parce que l’on doit s’attendre à ce que de nouveaux paramètres soient ajoutés dans le temps et la fonction réceptrice doit être capable d’accepter ces nouveaux paramètres.

Les récepteurs peuvent aussi être des fonctions asynchrones, avec la même signature mais déclarées comme `async def`:

```
async def my_receiver(sender, **kwargs):
    await asyncio.sleep(5)
    print("Request finished!")
```

Les signaux peuvent être envoyés de manière synchrone ou asynchrone, et les récepteurs s’adapteront automatiquement au style d’appel approprié. Voir [envoi de signaux](#sending-signals) pour plus d’informations.

### Connexion des fonctions réceptrices

Il y a deux façons de connecter une fonction réceptrice à un signal. Vous pouvez choisir l’option de la connexion manuelle :

```
from django.core.signals import request_finished

request_finished.connect(my_receiver)
```

L’autre possibilité est d’utiliser le décorateur [`receiver()`](#django.dispatch.receiver):

#### `receiver(signal, **kwargs)`

**Paramètres:** - `signal` – Un signal ou une liste de signaux auxquels connecter la fonction.
- `kwargs` – Autres paramètres nommés arbitraires à passer à la [fonction](#receiver-functions).

Voici comment faire la connexion avec le décorateur :

```
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.

> **À quel endroit ce code devrait-il se trouver ?**
>
> Strictement parlant, le code du signal et le code d’inscription peuvent se trouver n’importe où, même s’il est recommandé d’éviter le module racine de l’application et son module `models` pour minimiser les effets de bord de l’importation du code.
>
> In practice, signal receivers are usually defined in a `signals`
> submodule of the application they relate to. Signal receivers are
> connected in the [`ready()`](/fr/6.1/ref/applications/#django.apps.AppConfig.ready) method of your
> application [configuration class](/fr/6.1/ref/applications/#configuring-applications-ref). If
> you’re using the [`receiver()`](#django.dispatch.receiver) decorator, import the `signals`
> submodule inside [`ready()`](/fr/6.1/ref/applications/#django.apps.AppConfig.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)
> ```

> **Note**
>
> Il est possible que la méthode [`ready()`](/fr/6.1/ref/applications/#django.apps.AppConfig.ready) soit exécutée plus d’une fois durant les tests. Par conséquent, il est préférable [d’empêcher la duplication des signaux](#preventing-duplicate-signals), si votre récepteur est une méthode liée à une instance qui pourrait être recréée.

### Connexion aux signaux envoyés par des expéditeurs spécifiques

Certains signaux sont envoyés de nombreuses fois, mais vous n’êtes pas toujours intéressé à tous les recevoir. Par exemple, considérez le signal [`django.db.models.signals.pre_save`](/fr/6.1/ref/signals/#django.db.models.signals.pre_save) envoyé avant chaque enregistrement de modèle. La plupart du temps, vous n’avez pas besoin de savoir quand *chaque* modèle est enregistré, mais seulement pour un modèle *spécifique*.

Dans ces situations, vous pouvez inscrire une fonction pour qu’elle ne reçoive les signaux que de certains expéditeurs. Dans le cas de [`django.db.models.signals.pre_save`](/fr/6.1/ref/signals/#django.db.models.signals.pre_save), l’expéditeur sera la classe du modèle en cours d’enregistrement, il est donc possible d’indiquer que vous ne voulez recevoir que les signaux envoyés par certains modèles :

```
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): ...
```

La fonction `my_handler` ne sera appelée que lors de l’enregistrement d’une instance de `MyModel`.

Différents signaux utilisent différents objets comme expéditeurs ; il s’agit de consulter la [documentation des signaux intégrés](/fr/6.1/ref/signals/) pour plus de détails sur chaque signal.

### Prévention des signaux dupliqués

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")
```

## Définition et envoi de signaux

Les applications peuvent profiter de l’infrastructure des signaux et fournir leurs propres signaux.

> **Quand utiliser des signaux personnalisés**
>
> Les signaux sont des appels de fonctions implicites qui compliquent le débogage. Si l’expéditeur et le destinataire de votre signal personnalisé sont tous deux dans votre projet, il est alors préférable d’utiliser un appel de fonction explicite.

### Définition de signaux

#### `class Signal`

Tous les signaux sont des instances de [`django.dispatch.Signal`](#django.dispatch.Signal).

Par exemple :

```
import django.dispatch

pizza_done = django.dispatch.Signal()
```

Ceci déclare un signal `pizza_done`.

### Envoi de signaux

Il y a deux façons d’envoyer des signaux dans Django de manière snychrone.

#### `Signal.send(sender, **kwargs)`

#### `Signal.send_robust(sender, **kwargs)`

Les signaux peuvent aussi être envoyés de manière asynchrone.

#### `Signal.asend(sender, **kwargs)`

#### `Signal.asend_robust(sender, **kwargs)`

Pour envoyer un signal, appelez [`Signal.send()`](#django.dispatch.Signal.send), [`Signal.send_robust()`](#django.dispatch.Signal.send_robust), [`await Signal.asend()`](#django.dispatch.Signal.asend), or [`await Signal.asend_robust()`](#django.dispatch.Signal.asend_robust). Vous devez indiquer l’argument `sender` (qui est une classe la plupart du temps) et vous pouvez ajouter autant d’arguments nommés que vous le souhaitez.

Par exemple, voici comment envoyer notre signal `pizza_done`:

```
class PizzaStore:
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self.__class__, toppings=toppings, size=size)
        ...
```

Les quatre méthodes renvoient uns liste de paires de tuples `[(récepteur, réponse), ... ]` correspondant à la liste des fonctions réceptrices appelées et la valeur de leur réponse.

`send()` diffère de `send_robust()` par la manière dont les exceptions générées par les fonctions réceptrices sont traitées. `send()` n’intercepte *aucune* exception générée par les récepteurs ; elle laisse simplement les erreurs se propager. Il est donc possible que certains récepteurs ne soient pas notifiés par le signal en cas d’erreur.

`send_robust()` intercepte toutes les erreurs héritant de la classe `Exception` de Python et s’assure que tous les récepteurs soient notifiés par le signal. Si une erreur survient, l’instance d’erreur est renvoyée dans le tuple correspondant au récepteur qui a généré l’erreur.

Les traces de débogage sont présentes dans l’attribut `__traceback__` des erreurs renvoyées lors des appels à `send_robust()`.

`asend()` est semblable à `send()`, mais il s’agit d’une coroutine qu’il faut appeler par `await`:

```
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()`](/fr/6.1/topics/async/#asgiref.sync.sync_to_async) when invoked via `asend()`. Asynchronous
receivers will be called using [`async_to_sync()`](/fr/6.1/topics/async/#asgiref.sync.async_to_sync) when invoked via
`send()`. Similar to the [case for middleware](/fr/6.1/topics/async/#async-performance),
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`](https://docs.python.org/3/library/asyncio-task.html#asyncio.TaskGroup).

Tous les signaux intégrés à Django, sauf ceux faisant partie du cycle requête-réponse asynchrone, sont envoyés par [`Signal.send()`](#django.dispatch.Signal.send).

> **Changed in Django 6.1**
>
> In older versions, async receivers were executed via `asyncio.gather()`.

## Déconnexion des signaux

#### `Signal.disconnect(receiver=None, sender=None, dispatch_uid=None)`

Pour déconnecter un récepteur d’un signal, appelez [`Signal.disconnect()`](#django.dispatch.Signal.disconnect). Les paramètres sont identiques à ceux décrits pour [`Signal.connect()`](#django.dispatch.Signal.connect). La méthode renvoie `True` si un récepteur a été déconnecté, sinon `False`. Lorsque `sender` est transmis comme référence différée à `<app label>.<model>`, cette méthode renvoie toujours `None`.

Le paramètre `receiver` indique le récepteur inscrit qu’il s’agit de déconnecter. Il peut valoir `None` si `dispatch_uid` est utilisé pour identifier le récepteur.
