---
title: "Contraintes de bases de données spécifiques à PostgreSQL"
version: 6.0
locale: fr
source: https://docs.djangoproject.com/fr/6.0/ref/contrib/postgres/constraints/
canonical: https://djangodocs.dev/fr/6.0/ref/contrib/postgres/constraints/
---
# Contraintes de bases de données spécifiques à PostgreSQL

PostgreSQL offre des contraintes d’intégrité de données supplémentaires dans le module `django.contrib.postgres.constraints`. Elles sont ajoutées dans l’option [`Meta.constraints`](/fr/6.0/ref/models/options/#django.db.models.Options.constraints) des modèles.

## `ExclusionConstraint`

#### `class ExclusionConstraint(* (Keyword-only parameters separator (PEP 3102)), name, expressions, index_type=None, condition=None, deferrable=None, include=None, violation_error_code=None, violation_error_message=None)`

Crée une contrainte d’exclusion dans la base de données. En interne, PostgreSQL implémente les contraintes d’exclusion par des index. Le type d’index par défaut est [GiST](https://www.postgresql.org/docs/current/gist.html). Pour les utiliser, vous devez activer [l’extension btree\_gist](https://www.postgresql.org/docs/current/btree-gist.html) dans PostgreSQL. Vous pouvez installer l’extension par une opération de migration [`BtreeGistExtension`](/fr/6.0/ref/contrib/postgres/operations/#django.contrib.postgres.operations.BtreeGistExtension).

Si vous essayez d’insérer une nouvelle ligne qui entre en conflit avec une ligne existante, une erreur [`IntegrityError`](/fr/6.0/ref/exceptions/#django.db.IntegrityError) se produit. De même lorsqu’un conflit survient lors d’une mise à jour.

Les contraintes d’exclusion sont vérifiées durant la [validation des modèles](/fr/6.0/ref/models/instances/#validating-objects).

### `name`

#### `ExclusionConstraint.name`

Voir [`BaseConstraint.name`](/fr/6.0/ref/models/constraints/#django.db.models.BaseConstraint.name).

### `expressions`

#### `ExclusionConstraint.expressions`

Un itérable de tuples binaires. Le premier élément est une expression ou une chaîne. Le second élément est un opérateur SQL sous forme de chaîne. Pour éviter les erreurs syntaxiques, vous pouvez utiliser [`RangeOperators`](/fr/6.0/ref/contrib/postgres/fields/#django.contrib.postgres.fields.RangeOperators) qui fait correspondre les opérateurs à des chaînes. Par exemple

```
expressions = [
    ("timespan", RangeOperators.ADJACENT_TO),
    (F("room"), RangeOperators.EQUAL),
]
```

> **Restrictions sur les opérateurs.**
>
> Seuls des opérateurs commutatifs peuvent être utilisés dans des contraintes d’exclusion.

L’expression [`OpClass()`](/fr/6.0/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.OpClass) peut être utilisée pour indiquer une [classe d’opérateur](https://www.postgresql.org/docs/current/indexes-opclass.html) personnalisée pour les expressions de contrainte. Par exemple

```
expressions = [
    (OpClass("circle", name="circle_ops"), RangeOperators.OVERLAPS),
]
```

crée une contrainte d’exclusion sur `circle` en utilisant `circle_ops`.

### `index_type`

#### `ExclusionConstraint.index_type`

Le type d’index de la contrainte. La valeurs admises sont `GIST` ou `SPGIST`. Les correspondances ne tiennent pas compte de la casse. En cas d’absence, le type d’index par défaut est `GIST`.

### `condition`

#### `ExclusionConstraint.condition`

Un objet [`Q`](/fr/6.0/ref/models/querysets/#django.db.models.Q) qui indique la condition de restriction d’une contrainte à un sous-ensemble de lignes. Par exemple, `condition=Q(annule=False)`.

Ces conditions sont soumises aux mêmes restrictions de base de données que [`django.db.models.Index.condition`](/fr/6.0/ref/models/indexes/#django.db.models.Index.condition).

### `deferrable`

#### `ExclusionConstraint.deferrable`

Définissez ce paramètre pour créer une contrainte d’exclusion différable. Les valeurs acceptées sont `Deferrable.DEFERRED` ou `Deferrable.IMMEDIATE`. Par exemple

```
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import RangeOperators
from django.db.models import Deferrable

ExclusionConstraint(
    name="exclude_overlapping_deferred",
    expressions=[
        ("timespan", RangeOperators.OVERLAPS),
    ],
    deferrable=Deferrable.DEFERRED,
)
```

Par défaut, les contraintes ne sont pas différées. Une contrainte différée ne sera pas appliquée avant la fin de la transaction. Une contrainte immédiate sera appliquée immédiatement après chaque commande.

> **Warning**
>
> Les contraintes d’exclusion différées peuvent amener à des [performances réduites](https://www.postgresql.org/docs/current/sql-createtable.html#id-1.9.3.85.9.4).

### `include`

#### `ExclusionConstraint.include`

Une liste ou un tuple de noms de champs à inclure dans la contrainte d’exclusion de couverture, représentant des colonnes qui ne sont pas des clés. Cela permet des analyses en index pur avec des requêtes qui ne sélectionnent que les champs inclus ([`include`](#django.contrib.postgres.constraints.ExclusionConstraint.include)) et qui ne filtrent que sur les champs indexés ([`expressions`](#django.contrib.postgres.constraints.ExclusionConstraint.expressions)).

`include` est pris en charge par les index GiST. PostgreSQL 14+ prend aussi en charge `include` pour les index SP-GiST.

### `violation_error_code`

#### `ExclusionConstraint.violation_error_code`

Le code d’erreur utilisé lorsque `ValidationError` est générée pendant la [phase de validation des modèles](/fr/6.0/ref/models/instances/#validating-objects). Contient `None` par défaut.

### `violation_error_message`

Le message d’erreur utilisé lorsque `ValidationError` est générée pendant la [phase de validation des modèles](/fr/6.0/ref/models/instances/#validating-objects). Contient par défaut [`BaseConstraint.violation_error_message`](/fr/6.0/ref/models/constraints/#django.db.models.BaseConstraint.violation_error_message).

### Exemples

L’exemple suivant évite les chevauchements de réservations d’une même salle, sans tenir compte des réservations annulées

```
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateTimeRangeField, RangeOperators
from django.db import models
from django.db.models import Q

class Room(models.Model):
    number = models.IntegerField()

class Reservation(models.Model):
    room = models.ForeignKey("Room", on_delete=models.CASCADE)
    timespan = DateTimeRangeField()
    cancelled = models.BooleanField(default=False)

    class Meta:
        constraints = [
            ExclusionConstraint(
                name="exclude_overlapping_reservations",
                expressions=[
                    ("timespan", RangeOperators.OVERLAPS),
                    ("room", RangeOperators.EQUAL),
                ],
                condition=Q(cancelled=False),
            ),
        ]
```

Dans le cas où un modèle définit un intervalle avec deux champs, au lieu des types d’intervalle natifs de PostgreSQL, vous devriez écrire une expression qui utilise la fonction équivalente (par ex.  `TsTzRange()`), et utiliser les délimiteurs du champ. La plupart du temps, les délimiteurs seront `'[)'`, ce qui signifie que la limite inférieure est inclusive et la limite supérieure exclusive. Vous pouvez utiliser [`RangeBoundary`](/fr/6.0/ref/contrib/postgres/fields/#django.contrib.postgres.fields.RangeBoundary) qui fournit des correspondances d’expression pour les [limites d’intervalle](https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-INCLUSIVITY). Par exemple

```
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import (
    DateTimeRangeField,
    RangeBoundary,
    RangeOperators,
)
from django.db import models
from django.db.models import Func, Q

class TsTzRange(Func):
    function = "TSTZRANGE"
    output_field = DateTimeRangeField()

class Reservation(models.Model):
    room = models.ForeignKey("Room", on_delete=models.CASCADE)
    start = models.DateTimeField()
    end = models.DateTimeField()
    cancelled = models.BooleanField(default=False)

    class Meta:
        constraints = [
            ExclusionConstraint(
                name="exclude_overlapping_reservations",
                expressions=[
                    (
                        TsTzRange("start", "end", RangeBoundary()),
                        RangeOperators.OVERLAPS,
                    ),
                    ("room", RangeOperators.EQUAL),
                ],
                condition=Q(cancelled=False),
            ),
        ]
```
