---
title: "Champs de modèles spécifiques à PostgreSQL"
version: 5.1
locale: fr
source: https://docs.djangoproject.com/fr/5.1/ref/contrib/postgres/fields/
canonical: https://djangodocs.dev/fr/5.1/ref/contrib/postgres/fields/
---
# Champs de modèles spécifiques à PostgreSQL

Tous ces champs sont disponibles dans le module `django.contrib.postgres.fields`.

## Indexation de ces champs

Que ce soit avec [`Index`](/fr/5.1/ref/models/indexes/#django.db.models.Index) ou [`Field.db_index`](/fr/5.1/ref/models/fields/#django.db.models.Field.db_index), c’est un index B-tree qui est créé, ce qui n’est pas spécialement utile lors de requêtes sur des types de données complexes. Les index tels que [`GinIndex`](/fr/5.1/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.GinIndex) et [`GistIndex`](/fr/5.1/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.GistIndex) sont mieux adaptés, même si le choix de l’index dépend des requêtes effectivement utilisées. En général, GiST est un bon choix pour les [champs d’intervalle](#range-fields) et le champ [`HStoreField`](#django.contrib.postgres.fields.HStoreField), alors que GIN est souvent utile pour les champs [`ArrayField`](#django.contrib.postgres.fields.ArrayField) et `JSONField`.

## `ArrayField`

#### `class ArrayField(base_field, size=None, **options)`

Un champ pour stocker des listes de données. La plupart des types de champs peuvent être utilisés ; passez une autre instance de champ dans l’attribut [`base_field`](#django.contrib.postgres.fields.ArrayField.base_field). Vous pouvez aussi indiquer une taille dans [`size`](#django.contrib.postgres.fields.ArrayField.size). `ArrayField` peut être imbriqué pour stocker des tableaux multidimensionnels.

Si vous donnez une valeur [`default`](/fr/5.1/ref/models/fields/#django.db.models.Field.default) à ce champ, assurez-vous que ce soit un objet exécutable tel que `list` (pour une valeur par défaut vide) ou un objet exécutable qui renvoie une liste (par exemple une fonction). L’utilisation de `default=[]` n’est pas correct car cela crée une valeur par défaut mutante qui est partagée entre les instances de `ArrayField`.

#### `base_field`

Ce paramètre est obligatoire.

Définit le type de données sous-jacent et le comportement du tableau. Il devrait s’agir d’une instance d’une sous-classe de [`Field`](/fr/5.1/ref/models/fields/#django.db.models.Field). Par exemple, cela pourrait être un [`IntegerField`](/fr/5.1/ref/models/fields/#django.db.models.IntegerField) ou un [`CharField`](/fr/5.1/ref/models/fields/#django.db.models.CharField). La plupart des types de champs sont autorisés, à l’exception de ceux qui gèrent des données relationnelles ([`ForeignKey`](/fr/5.1/ref/models/fields/#django.db.models.ForeignKey), [`OneToOneField`](/fr/5.1/ref/models/fields/#django.db.models.OneToOneField) et [`ManyToManyField`](/fr/5.1/ref/models/fields/#django.db.models.ManyToManyField)) et des champs fichiers ([`FileField`](/fr/5.1/ref/models/fields/#django.db.models.FileField) et [`ImageField`](/fr/5.1/ref/models/fields/#django.db.models.ImageField)).

Il est possible d’imbriquer des champs tabulaires, c’est-à-dire que `base_field` peut contenir une instance de `ArrayField`. Par exemple :

```
from django.contrib.postgres.fields import ArrayField
from django.db import models

class ChessBoard(models.Model):
    board = ArrayField(
        ArrayField(
            models.CharField(max_length=10, blank=True),
            size=8,
        ),
        size=8,
    )
```

La transformation de valeurs entre la base de données et le modèle, la validation de données et la configuration ainsi que la sérialisation sont tous délégués au champ de base sous-jacent.

#### `size`

Ce paramètre est facultatif.

Si présent, le tableau aura la taille maximale indiquée. Cette valeur est transmise à la base de données, même si PostgreSQL n’applique actuellement pas cette restriction.

> **Note**
>
> Lors de l’imbrication de champs `ArrayField`, que le paramètre `size` soit défini ou non, PostgreSQL exige que les tableaux soient rectangulaires :
>
> ```
> from django.contrib.postgres.fields import ArrayField
> from django.db import models
>
>
> class Board(models.Model):
>     pieces = ArrayField(ArrayField(models.IntegerField()))
>
>
> # Valid
> Board(
>     pieces=[
>         [2, 3],
>         [2, 1],
>     ]
> )
>
> # Not valid
> Board(
>     pieces=[
>         [2, 3],
>         [2],
>     ]
> )
> ```
>
> Si des formes irrégulières sont nécessaires, le sous-champ doit pouvoir être nul et les valeurs doivent être complétées avec `None`.

### Interrogation de `ArrayField`

Il existe plusieurs recherches et transformations spécifiques au champ [`ArrayField`](#django.contrib.postgres.fields.ArrayField). Nous allons utiliser le modèle d’exemple suivant :

```
from django.contrib.postgres.fields import ArrayField
from django.db import models

class Post(models.Model):
    name = models.CharField(max_length=200)
    tags = ArrayField(models.CharField(max_length=200), blank=True)

    def __str__(self):
        return self.name
```

#### `contains`

La recherche [`contains`](/fr/5.1/ref/models/querysets/#std-fieldlookup-contains) est surchargée pour [`ArrayField`](#django.contrib.postgres.fields.ArrayField). Les objets renvoyés sont ceux pour qui les valeurs transmises forment un sous-ensemble des données. Elle utilise l’opérateur SQL `@>`. Par exemple :

```pycon
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
>>> Post.objects.create(name="Second post", tags=["thoughts"])
>>> Post.objects.create(name="Third post", tags=["tutorial", "django"])

>>> Post.objects.filter(tags__contains=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__contains=["django"])
<QuerySet [<Post: First post>, <Post: Third post>]>

>>> Post.objects.filter(tags__contains=["django", "thoughts"])
<QuerySet [<Post: First post>]>
```

#### `contained_by`

Il s’agit de l’inverse de la recherche [`contains`](#std-fieldlookup-arrayfield.contains), les objets renvoyés sont ceux pour qui les données forment un sous-ensemble des valeurs transmises. Elle utilise l’opérateur SQL `<@`. Par exemple :

```pycon
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
>>> Post.objects.create(name="Second post", tags=["thoughts"])
>>> Post.objects.create(name="Third post", tags=["tutorial", "django"])

>>> Post.objects.filter(tags__contained_by=["thoughts", "django"])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__contained_by=["thoughts", "django", "tutorial"])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
```

#### `overlap`

Renvoie les objets dont les données contiennent au moins une valeur en commun avec celles transmises. Utilise l’opérateur SQL `&&`. Par exemple :

```pycon
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
>>> Post.objects.create(name="Second post", tags=["thoughts", "tutorial"])
>>> Post.objects.create(name="Third post", tags=["tutorial", "django"])

>>> Post.objects.filter(tags__overlap=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__overlap=["thoughts", "tutorial"])
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>

>>> Post.objects.filter(tags__overlap=Post.objects.values_list("tags"))
<QuerySet [<Post: First post>, <Post: Second post>, <Post: Third post>]>
```

#### `len`

Renvoie la longueur du tableau. Les recherches disponibles à la suite de celle-ci sont celles qui sont disponibles pour les champs [`IntegerField`](/fr/5.1/ref/models/fields/#django.db.models.IntegerField). Par exemple :

```pycon
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
>>> Post.objects.create(name="Second post", tags=["thoughts"])

>>> Post.objects.filter(tags__len=1)
<QuerySet [<Post: Second post>]>
```

#### Transformations d’indice

Les transformations d’index indicent dans les tableaux. Tout nombre entier non négatif est utilisable. Aucune erreur n’est produite si l’indice dépasse la taille [`size`](#django.contrib.postgres.fields.ArrayField.size) du tableau. Les recherches disponibles à la suite de la transformation sont celles du champ [`base_field`](#django.contrib.postgres.fields.ArrayField.base_field). Par exemple :

```pycon
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
>>> Post.objects.create(name="Second post", tags=["thoughts"])

>>> Post.objects.filter(tags__0="thoughts")
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__1__iexact="Django")
<QuerySet [<Post: First post>]>

>>> Post.objects.filter(tags__276="javascript")
<QuerySet []>
```

> **Note**
>
> PostgreSQL utilise l’indiçage à partir de 1 pour les champs de type tableau lors de l’écriture de SQL brut. Cependant, ces indices ainsi que ceux utilisés dans les [`segmentations`](#std-fieldlookup-arrayfield.slice) emploient des indices depuis 0 afin de rester cohérent avec Python.

#### Transformations de segmentation

Les transformations de segmentation segmentent dans les tableaux. Toute paire de nombres entiers non négatifs peut être utilisée, séparée par un seul soulignement. Les recherches disponibles après la transformation ne changent pas. Par exemple :

```pycon
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
>>> Post.objects.create(name="Second post", tags=["thoughts"])
>>> Post.objects.create(name="Third post", tags=["django", "python", "thoughts"])

>>> Post.objects.filter(tags__0_1=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>

>>> Post.objects.filter(tags__0_2__contains=["thoughts"])
<QuerySet [<Post: First post>, <Post: Second post>]>
```

> **Note**
>
> PostgreSQL utilise l’indiçage à partir de 1 pour les champs de type tableau lors de l’écriture de SQL brut. Cependant, ces segmentations ainsi que celles utilisées dans les [`indices`](#std-fieldlookup-arrayfield.index) emploient des indices depuis 0 afin de rester cohérent avec Python.

> **Indices et segmentations avec les tableaux multidimensionnels**
>
> Le comportement de PostgreSQL est plutôt ésotérique lorsqu’il s’agit d’indicer ou de segmenter des tableaux à plusieurs dimensions. L’emploi des indices pour atteindre une donnée imbriquée fonctionne dans tous les cas, mais la plupart des autres segmentations se comportent bizarrement au niveau de la base de données et ne peuvent pas être prises en charge de manière cohérente et logique par Django.

## `HStoreField`

#### `class HStoreField(**options)`

Un champ pour stocker des paires clé-valeur. Le type de données Python utilisé est un dictionnaire `dict`. Les clés doivent être des chaînes et les valeurs peuvent être soit des chaînes, soit la valeur nulle (`None` en Python).

Pour utiliser ce champ, il faut :

1. Ajouter `'django.contrib.postgres'` à votre réglage [`INSTALLED_APPS`](/fr/5.1/ref/settings/#std-setting-INSTALLED_APPS).
2. [Configurer l’extension hstore](/fr/5.1/ref/contrib/postgres/operations/#create-postgresql-extensions) dans PostgreSQL.

Vous verrez une erreur du genre `can't adapt type 'dict'` si vous omettez la première étape, ou `type "hstore" does not exist` si vous omettez la seconde.

> **Note**
>
> Parfois, il est utile de pouvoir limiter les clés admises comme valides pour un champ donné. Cela peut se faire à l’aide de [`KeysValidator`](/fr/5.1/ref/contrib/postgres/validators/#django.contrib.postgres.validators.KeysValidator).

### Interrogation de `HStoreField`

En plus de la possibilité d’interroger en fonction de la clé, il existe quelques recherches tout exprès pour les champs `HStoreField`.

Nous allons utiliser le modèle d’exemple suivant :

```
from django.contrib.postgres.fields import HStoreField
from django.db import models

class Dog(models.Model):
    name = models.CharField(max_length=200)
    data = HStoreField()

    def __str__(self):
        return self.name
```

#### Recherches par clé

Pour rechercher en fonction d’une clé donnée, utilisez cette clé comme nom de requête :

```pycon
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
>>> Dog.objects.create(name="Meg", data={"breed": "collie"})

>>> Dog.objects.filter(data__breed="collie")
<QuerySet [<Dog: Meg>]>
```

Il est possible d’enchaîner d’autres recherches après une recherche par clé :

```pycon
>>> Dog.objects.filter(data__breed__contains="l")
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
```

ou utilisez des expressions `F()` pour annoter une valeur de clé. Par exemple :

```pycon
>>> from django.db.models import F
>>> rufus = Dog.objects.annotate(breed=F("data__breed"))[0]
>>> rufus.breed
'labrador'
```

Si la clé avec laquelle vous souhaitez rechercher entre en conflit avec le nom d’une recherche existante, vous devez utiliser la recherche [`hstorefield.contains`](#std-fieldlookup-hstorefield.contains) à la place.

> **Note**
>
> Les transformations de clé peuvent également être suivies par des expressions [`contains`](/fr/5.1/ref/models/querysets/#std-fieldlookup-contains), [`icontains`](/fr/5.1/ref/models/querysets/#std-fieldlookup-icontains), [`endswith`](/fr/5.1/ref/models/querysets/#std-fieldlookup-endswith), [`iendswith`](/fr/5.1/ref/models/querysets/#std-fieldlookup-iendswith), [`iexact`](/fr/5.1/ref/models/querysets/#std-fieldlookup-iexact), [`regex`](/fr/5.1/ref/models/querysets/#std-fieldlookup-regex), [`iregex`](/fr/5.1/ref/models/querysets/#std-fieldlookup-iregex), [`startswith`](/fr/5.1/ref/models/querysets/#std-fieldlookup-startswith) et [`istartswith`](/fr/5.1/ref/models/querysets/#std-fieldlookup-istartswith).

> **Warning**
>
> Comme n’importe quelle chaîne peut être une clé d’une valeur `hstore`, toute recherche autre que celles mentionnées ci-dessous sera interprétée comme une recherche par clé. Aucune erreur n’est produite. Faites spécialement attention aux erreurs de frappe et vérifiez systématiquement que vos requêtes fonctionnent correctement.

#### `contains`

La recherche [`contains`](/fr/5.1/ref/models/querysets/#std-fieldlookup-contains) est surchargée pour [`HStoreField`](#django.contrib.postgres.fields.HStoreField). Les objets renvoyés sont ceux pour qui le dictionnaire de paires clé-valeur est totalement contenu dans le champ. Elle utilise l’opérateur SQL `@>`. Par exemple :

```pycon
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
>>> Dog.objects.create(name="Fred", data={})

>>> Dog.objects.filter(data__contains={"owner": "Bob"})
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>

>>> Dog.objects.filter(data__contains={"breed": "collie"})
<QuerySet [<Dog: Meg>]>
```

#### `contained_by`

Il s’agit de l’inverse de la recherche [`contains`](#std-fieldlookup-hstorefield.contains), les objets renvoyés sont ceux pour qui les paires de clé-valeur forment un sous-ensemble des valeurs transmises. Elle utilise l’opérateur SQL `<@`. Par exemple :

```pycon
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador", "owner": "Bob"})
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})
>>> Dog.objects.create(name="Fred", data={})

>>> Dog.objects.filter(data__contained_by={"breed": "collie", "owner": "Bob"})
<QuerySet [<Dog: Meg>, <Dog: Fred>]>

>>> Dog.objects.filter(data__contained_by={"breed": "collie"})
<QuerySet [<Dog: Fred>]>
```

#### `has_key`

Renvoie les objets dont les données contiennent la clé indiquée. Utilise l’opérateur SQL `?`. Par exemple :

```pycon
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})

>>> Dog.objects.filter(data__has_key="owner")
<QuerySet [<Dog: Meg>]>
```

#### `has_any_keys`

Renvoie les objets dont les données contiennent au moins une des clés indiquées. Utilise l’opérateur SQL `?|`. Par exemple :

```pycon
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
>>> Dog.objects.create(name="Meg", data={"owner": "Bob"})
>>> Dog.objects.create(name="Fred", data={})

>>> Dog.objects.filter(data__has_any_keys=["owner", "breed"])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
```

#### `has_keys`

Renvoie les objets dont les données contiennent toutes les clés indiquées. Utilise l’opérateur SQL `?&`. Par exemple :

```pycon
>>> Dog.objects.create(name="Rufus", data={})
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})

>>> Dog.objects.filter(data__has_keys=["breed", "owner"])
<QuerySet [<Dog: Meg>]>
```

#### `keys`

Renvoie l’ensemble des clés des objets concernés. Notez que l’ordre n’est pas garanti, ce qui fait que cette transformation est surtout utile quand elle est combinée à des recherches sur [`ArrayField`](#django.contrib.postgres.fields.ArrayField). Utilise la fonction SQL `akeys()`. Par exemple :

```pycon
>>> Dog.objects.create(name="Rufus", data={"toy": "bone"})
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})

>>> Dog.objects.filter(data__keys__overlap=["breed", "toy"])
<QuerySet [<Dog: Rufus>, <Dog: Meg>]>
```

#### `values`

Renvoie l’ensemble des valeurs des objets concernés. Notez que l’ordre n’est pas garanti, ce qui fait que cette transformation est surtout utile quand elle est combinée à des recherches sur [`ArrayField`](#django.contrib.postgres.fields.ArrayField). Utilise la fonction SQL `avals()`. Par exemple :

```pycon
>>> Dog.objects.create(name="Rufus", data={"breed": "labrador"})
>>> Dog.objects.create(name="Meg", data={"breed": "collie", "owner": "Bob"})

>>> Dog.objects.filter(data__values__contains=["collie"])
<QuerySet [<Dog: Meg>]>
```

## Champs d’intervalle

Il existe cinq types de champs d’intervalle, correspondant au types d’intervalles natifs de PostgreSQL. Ces champs sont utilisés pour stocker un intervalle de valeurs ; par exemple, l’heure de début et de fin d’un événement ou l’intervalle des âges appropriés à une activité.

Tous les champs d’intervalle produisent des objets [psycopg Range](https://www.psycopg.org/psycopg3/docs/basic/pgtypes.html#adapt-range) en Python, mais acceptent aussi des tuples en entrée si aucune information de limite n’est nécessaire. Par défaut, la limite inférieure est incluse et la limite supérieure exclue ; c’est-à-dire `[)` (consultez la documentation PostgreSQL pour plus de détails sur les [différentes limites](https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-IO)). Les limites par défaut peuvent être modifiées pour les champs d’intervalle de type non discret ([`DateTimeRangeField`](#django.contrib.postgres.fields.DateTimeRangeField) et [`DecimalRangeField`](#django.contrib.postgres.fields.DecimalRangeField)) en utilisant l’argument `default_bounds`.

> **PostgreSQL normalise les intervalles sans contenu en intervalles vides**
>
> Un intervalle avec valeurs égales et limite inférieure inclusive et limite supérieure exclusive, tel que `Range(datetime.date(2005, 6, 21), datetime.date(2005, 6, 21))` ou `[4, 4)` n’a pas de contenu. PostgreSQL normalise de telles valeurs en intervalles vides lors de l’enregistrement dans la base, ce qui fait que les valeurs limites d’origine de début et de fin sont perdues. Consultez la [documentation de PostgreSQL pour plus de détails](https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-IO).

### `IntegerRangeField`

#### `class IntegerRangeField(**options)`

Stocke un intervalle de nombres entiers. Basé sur un [`IntegerField`](/fr/5.1/ref/models/fields/#django.db.models.IntegerField). Représenté par un `int4range` dans la base de données et un `django.db.backends.postgresql.psycopg_any.NumericRange` en Python.

Quelles que soient les limites indiquées lors de l’enregistrement des données, PostgreSQL renvoie toujours un intervalle dans sa forme canonique qui inclut la limite inférieure et exclut la limite supérieure, c’est-à-dire `[)`.

### `BigIntegerRangeField`

#### `class BigIntegerRangeField(**options)`

Stocke un intervalle de grands nombres entiers. Basé sur un [`BigIntegerField`](/fr/5.1/ref/models/fields/#django.db.models.BigIntegerField). Représenté par un `int8range` dans la base de données et un `django.db.backends.postgresql.psycopg_any.NumericRange` en Python.

Quelles que soient les limites indiquées lors de l’enregistrement des données, PostgreSQL renvoie toujours un intervalle dans sa forme canonique qui inclut la limite inférieure et exclut la limite supérieure, c’est-à-dire `[)`.

### `DecimalRangeField`

#### `class DecimalRangeField(default_bounds='[)', **options)`

Stocke un intervalle de nombres à virgule flottante. Basé sur un [`DecimalField`](/fr/5.1/ref/models/fields/#django.db.models.DecimalField). Représenté par un `numrange` dans la base de données et un `django.db.backends.postgresql.psycopg_any.NumericRange` en Python.

#### `default_bounds`

Facultatif. La valeur de `bounds` pour les entrées de type liste et tuple. La valeur par défaut est d’inclure la limite inférieure et d’exclure la limite supérieure, donc `[)` (voir la documentation PostgreSQL pour plus de détails sur les [différentes limites](https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-IO)). `default_bounds` n’est pas utilisé pour les entrées  `django.db.backends.postgresql.psycopg_any.NumericRange`.

### `DateTimeRangeField`

#### `class DateTimeRangeField(default_bounds='[)', **options)`

Stocke un intervalle d’horodatages. Basé sur un [`DateTimeField`](/fr/5.1/ref/models/fields/#django.db.models.DateTimeField). Représenté par un `tstzrange` dans la base de données et un `django.db.backends.postgresql.psycopg_any.DateTimeTZRange` en Python.

#### `default_bounds`

Facultatif. La valeur de `bounds` pour les entrées de type liste et tuple. La valeur par défaut est d’inclure la limite inférieure et d’exclure la limite supérieure, donc `[)` (voir la documentation PostgreSQL pour plus de détails sur les [différentes limites](https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-IO)). `default_bounds` n’est pas utilisé pour les entrées  `django.db.backends.postgresql.psycopg_any.DateTimeTZRange`.

### `DateRangeField`

#### `class DateRangeField(**options)`

Stocke un intervalle de dates. Basé sur un [`DateField`](/fr/5.1/ref/models/fields/#django.db.models.DateField). Représenté par un `daterange` dans la base de données et un `django.db.backends.postgresql.psycopg_any.DateRange` en Python.

Quelles que soient les limites indiquées lors de l’enregistrement des données, PostgreSQL renvoie toujours un intervalle dans sa forme canonique qui inclut la limite inférieure et exclut la limite supérieure, c’est-à-dire `[)`.

### Interrogation de champs d’intervalle

Il existe un certain nombre de recherches et de transformations spécifiques aux champs d’intervalle. Ils sont disponibles pour tous les champs ci-dessus, mais nous allons utiliser le modèle d’exemple suivant :

```
from django.contrib.postgres.fields import IntegerRangeField
from django.db import models

class Event(models.Model):
    name = models.CharField(max_length=200)
    ages = IntegerRangeField()
    start = models.DateTimeField()

    def __str__(self):
        return self.name
```

Nous allons aussi utiliser les objets d’exemple suivants :

```pycon
>>> import datetime
>>> from django.utils import timezone
>>> now = timezone.now()
>>> Event.objects.create(name="Soft play", ages=(0, 10), start=now)
>>> Event.objects.create(
...     name="Pub trip", ages=(21, None), start=now - datetime.timedelta(days=1)
... )
```

et `NumericRange`:

```
>>> from django.db.backends.postgresql.psycopg_any import NumericRange
```

#### Fonctions de contenance

Comme pour les autres champs PostgreSQL, trois opérateurs de contenance standard sont disponibles : `contains`, `contained_by` et `overlap`, utilisant respectivement les opérateurs SQL `@>`, `<@` et `&&`.

##### `contains`

```
>>> Event.objects.filter(ages__contains=NumericRange(4, 5))
<QuerySet [<Event: Soft play>]>
```

##### `contained_by`

```
>>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
<QuerySet [<Event: Soft play>]>
```

La recherche `contained_by` est aussi disponible pour les types de champ autres que intervalle : [`SmallAutoField`](/fr/5.1/ref/models/fields/#django.db.models.SmallAutoField), [`AutoField`](/fr/5.1/ref/models/fields/#django.db.models.AutoField), [`BigAutoField`](/fr/5.1/ref/models/fields/#django.db.models.BigAutoField), [`SmallIntegerField`](/fr/5.1/ref/models/fields/#django.db.models.SmallIntegerField), [`IntegerField`](/fr/5.1/ref/models/fields/#django.db.models.IntegerField), [`BigIntegerField`](/fr/5.1/ref/models/fields/#django.db.models.BigIntegerField), [`DecimalField`](/fr/5.1/ref/models/fields/#django.db.models.DecimalField), [`FloatField`](/fr/5.1/ref/models/fields/#django.db.models.FloatField), [`DateField`](/fr/5.1/ref/models/fields/#django.db.models.DateField) et [`DateTimeField`](/fr/5.1/ref/models/fields/#django.db.models.DateTimeField). Par exemple :

```pycon
>>> from django.db.backends.postgresql.psycopg_any import DateTimeTZRange
>>> Event.objects.filter(
...     start__contained_by=DateTimeTZRange(
...         timezone.now() - datetime.timedelta(hours=1),
...         timezone.now() + datetime.timedelta(hours=1),
...     ),
... )
<QuerySet [<Event: Soft play>]>
```

##### `overlap`

```
>>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
<QuerySet [<Event: Soft play>]>
```

#### Fonctions de comparaison

Les champs d’intervalle prennent en charge les recherches standard : [`lt`](/fr/5.1/ref/models/querysets/#std-fieldlookup-lt), [`gt`](/fr/5.1/ref/models/querysets/#std-fieldlookup-gt), [`lte`](/fr/5.1/ref/models/querysets/#std-fieldlookup-lte) et [`gte`](/fr/5.1/ref/models/querysets/#std-fieldlookup-gte). Elles ne sont pas particulièrement utiles, la comparaison s’opère d’abord sur la limite inférieure et si nécessaire, sur la limite supérieure ensuite. C’est également la stratégie adoptée pour trier selon un champ d’intervalle. Il est recommandé d’utiliser plutôt les opérateurs spécifiques de comparaison d’intervalle.

##### `fully_lt`

Les intervalles renvoyés sont strictement inférieurs à l’intervalle transmis. En d’autres termes, tous les points d’un intervalle renvoyé sont plus petits que tous ceux de l’intervalle transmis.

```
>>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
<QuerySet [<Event: Soft play>]>
```

##### `fully_gt`

Les intervalles renvoyés sont strictement supérieurs à l’intervalle transmis. En d’autres termes, tous les points d’un intervalle renvoyé sont plus grands que tous ceux de l’intervalle transmis.

```
>>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15))
<QuerySet [<Event: Pub trip>]>
```

##### `not_lt`

Les intervalles renvoyés ne contiennent aucun élément plus petit que ceux de l’intervalle transmis, c’est-à-dire que la limite inférieure d’un intervalle renvoyé est au moins égale à la limite inférieure de l’intervalle transmis.

```
>>> Event.objects.filter(ages__not_lt=NumericRange(0, 15))
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
```

##### `not_gt`

Les intervalles renvoyés ne contiennent aucun élément plus grand que ceux de l’intervalle transmis, c’est-à-dire que la limite supérieure d’un intervalle renvoyé n’est pas plus grande que la limite supérieure de l’intervalle transmis.

```
>>> Event.objects.filter(ages__not_gt=NumericRange(3, 10))
<QuerySet [<Event: Soft play>]>
```

##### `adjacent_to`

Les intervalles renvoyés partagent une limite avec l’intervalle transmis.

```
>>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21))
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
```

#### Interrogation à l’aide des limites

Les champs d’intervalle acceptent plusieurs requêtes supplémentaires.

##### `startswith`

Les objets renvoyés possèdent la limite inférieure indiquée. Peut être suivie par des recherches valides pour le champ de base.

```
>>> Event.objects.filter(ages__startswith=21)
<QuerySet [<Event: Pub trip>]>
```

##### `endswith`

Les objets renvoyés possèdent la limite supérieure indiquée. Peut être suivie par des recherches valides pour le champ de base.

```
>>> Event.objects.filter(ages__endswith=10)
<QuerySet [<Event: Soft play>]>
```

##### `isempty`

Les objets renvoyés sont des intervalles vides. Peut être suivie par des recherches valides pour un champ [`BooleanField`](/fr/5.1/ref/models/fields/#django.db.models.BooleanField).

```
>>> Event.objects.filter(ages__isempty=True)
<QuerySet []>
```

##### `lower_inc`

Renvoie les objets dont la limite inférieure est incluse ou exclue, selon la valeur booléenne transmise. Peut être suivie par des recherches valides pour un champ [`BooleanField`](/fr/5.1/ref/models/fields/#django.db.models.BooleanField).

```
>>> Event.objects.filter(ages__lower_inc=True)
<QuerySet [<Event: Soft play>, <Event: Pub trip>]>
```

##### `lower_inf`

Renvoie les objets dont la limite inférieure est illimitée (infinie) ou limitée, selon la valeur booléenne transmise. Peut être suivie par des recherches valides pour un champ [`BooleanField`](/fr/5.1/ref/models/fields/#django.db.models.BooleanField).

```
>>> Event.objects.filter(ages__lower_inf=True)
<QuerySet []>
```

##### `upper_inc`

Renvoie les objets dont la limite supérieure est incluse ou exclue, selon la valeur booléenne transmise. Peut être suivie par des recherches valides pour un champ [`BooleanField`](/fr/5.1/ref/models/fields/#django.db.models.BooleanField).

```
>>> Event.objects.filter(ages__upper_inc=True)
<QuerySet []>
```

##### `upper_inf`

Renvoie les objets dont la limite supérieure est illimitée (infinie) ou limitée, selon la valeur booléenne transmise. Peut être suivie par des recherches valides pour un champ [`BooleanField`](/fr/5.1/ref/models/fields/#django.db.models.BooleanField).

```
>>> Event.objects.filter(ages__upper_inf=True)
<QuerySet [<Event: Pub trip>]>
```

### Définition de ses propres types d’intervalle

PostgreSQL permet de définir ses propres types d’intervalle. Les implémentations de champs de modèle et de formulaire de Django utilisent les classes de base ci-dessous, et `psycopg` propose une fonction [`register_range()`](https://www.psycopg.org/psycopg3/docs/basic/pgtypes.html#psycopg.types.range.register_range) pour permettre l’utilisation de types d’intervalle personnalisés.

#### `class RangeField(**options)`

Classe de base pour les champs de modèle de type intervalle.

#### `base_field`

La classe de champ de modèle à utiliser.

#### `range_type`

Le type d’intervalle à utiliser.

#### `form_field`

La classe de champ de formulaire à utiliser. Doit être une sous-classe de [`django.contrib.postgres.forms.BaseRangeField`](#django.contrib.postgres.fields.django.contrib.postgres.forms.BaseRangeField).

#### `class django.contrib.postgres.forms.BaseRangeField`

Classe de base pour les champs de formulaire de type intervalle.

#### `base_field`

Le champ de formulaire à utiliser.

#### `range_type`

Le type d’intervalle à utiliser.

### Opérateurs d’intervalle

#### `class RangeOperators`

PostgreSQL fournit un ensemble d’opérateurs SQL pouvant être utilisés avec les types de données intervalle (voir la [documentation PostgreSQL](https://www.postgresql.org/docs/current/functions-range.html#RANGE-OPERATORS-TABLE) pour tous les détails sur les opérateurs d’intervalle). Cette classe est pensée comme une méthode utilitaire pour éviter des fautes de frappe. Les noms d’opérateurs se recoupent avec les noms de leur opérateur de requête correspondant.

```python
class RangeOperators:
    EQUAL = "="
    NOT_EQUAL = "<>"
    CONTAINS = "@>"
    CONTAINED_BY = "<@"
    OVERLAPS = "&&"
    FULLY_LT = "<<"
    FULLY_GT = ">>"
    NOT_LT = "&>"
    NOT_GT = "&<"
    ADJACENT_TO = "-|-"
```

### Expressions RangeBoundary()

#### `class RangeBoundary(inclusive_lower=True, inclusive_upper=False)`

#### `inclusive_lower`

Si `True` (par défaut), la limite inférieure est inclusive (`'['`), sinon elle est exclusive (`'('`).

#### `inclusive_upper`

Si `False` (par défaut), la limite supérieure est exclusive (`'('`), sinon elle est inclusive (`']'`).

Une expression `RangeBoundary()` représente les limites d’un intervalle. Elle peut être utilisée avec une fonction d’intervalle personnalisée qui reçoit des limites, par exemple pour définir [`ExclusionConstraint`](/fr/5.1/ref/contrib/postgres/constraints/#django.contrib.postgres.constraints.ExclusionConstraint). Voir la [documentation PostgreSQL](https://www.postgresql.org/docs/current/rangetypes.html#RANGETYPES-INCLUSIVITY) pour tous les détails.
