---
title: "Fonctions de base de données"
version: 1.10
locale: fr
source: https://docs.djangoproject.com/fr/1.10/ref/models/database-functions/
canonical: https://djangodocs.dev/fr/1.10/ref/models/database-functions/
---
# Fonctions de base de données

Les classes documentées ci-dessous permettent d’exploiter dans Django les fonctions fournies par la base de données sous-jacente telles que les annotations, les agrégations ou les filtres. Les fonctions sont également des [expressions](/fr/1.10/ref/models/expressions/), elles peuvent donc être utilisées et combinées avec d’autres expressions comme les [fonctions d’agrégation](/fr/1.10/ref/models/querysets/#aggregation-functions).

Nous allons utiliser le modèle suivant dans les exemples de chaque fonction :

```
class Author(models.Model):
    name = models.CharField(max_length=50)
    age = models.PositiveIntegerField(null=True, blank=True)
    alias = models.CharField(max_length=50, null=True, blank=True)
    goes_by = models.CharField(max_length=50, null=True, blank=True)
```

Nous ne recommandons généralement pas de définir `null=True` pour les champs `CharField` car cela permet au champ de posséder deux valeurs « vides » différentes, mais nous l’utilisons ici pour l’exemple `Coalesce` ci-dessous.

## `Cast`

#### `class Cast(expression, output_field)`

> **New in Django 1.10**

Force le type de résultat de `expression` à celui de `output_field`.

Exemple d’utilisation :

```
>>> from django.db.models import FloatField
>>> from django.db.models.functions import Cast
>>> Value.objects.create(integer=4)
>>> value = Value.objects.annotate(as_float=Cast('integer', FloatField())).get()
>>> print(value.as_float)
4.0
```

## `Coalesce`

#### `class Coalesce(*expressions, **extra)`

Accepte une liste d’au moins deux noms de champ ou expressions et renvoie la première valeur non nulle (notez qu’une chaîne vide n’est pas considérée comme une valeur nulle). Chaque paramètre doit être d’un type similaire ; si vous mélangez des textes et des nombres, la base de données produira une erreur.

Exemples d’utilisation :

```
>>> # Get a screen name from least to most public
>>> from django.db.models import Sum, Value as V
>>> from django.db.models.functions import Coalesce
>>> Author.objects.create(name='Margaret Smith', goes_by='Maggie')
>>> author = Author.objects.annotate(
...    screen_name=Coalesce('alias', 'goes_by', 'name')).get()
>>> print(author.screen_name)
Maggie

>>> # Prevent an aggregate Sum() from returning None
>>> aggregated = Author.objects.aggregate(
...    combined_age=Coalesce(Sum('age'), V(0)),
...    combined_age_default=Sum('age'))
>>> print(aggregated['combined_age'])
0
>>> print(aggregated['combined_age_default'])
None
```

> **Warning**
>
> Avec MySQL, il est possible qu’une valeur Python transmise à `Coalesce` soit convertie en un type incorrect, sauf dans le cas où le bon type de base de données est explicitement forcé :
>
> ```
> >>> from django.db.models import DateTimeField
> >>> from django.db.models.functions import Cast, Coalesce
> >>> from django.utils import timezone
> >>> now = timezone.now()
> >>> Coalesce('updated', Cast(now, DateTimeField()))
> ```

## `Concat`

#### `class Concat(*expressions, **extra)`

Accepte une liste d’au moins deux champs textes ou expressions et renvoie la concaténation de ces paramètres. Chaque paramètre doit être de type texte ou caractère. Si vous voulez concaténer un champ `TextField()` avec un champ `CharField()`, prenez alors la précaution d’indiquer à Django que le résultat `output_field` sera un champ `TextField()`. C’est aussi nécessaire lors de la concaténation avec une valeur `Value` comme dans l’exemple ci-dessous.

Le résultat de cette fonction n’est jamais nul. Pour les moteurs où un paramètre nul aboutit à ce que toute l’expression devienne nulle, Django s’assure que chaque partie nulle est préalablement convertie en chaîne vide.

Exemple d’utilisation :

```
>>> # Get the display name as "name (goes_by)"
>>> from django.db.models import CharField, Value as V
>>> from django.db.models.functions import Concat
>>> Author.objects.create(name='Margaret Smith', goes_by='Maggie')
>>> author = Author.objects.annotate(
...    screen_name=Concat('name', V(' ('), 'goes_by', V(')'),
...    output_field=CharField())).get()
>>> print(author.screen_name)
Margaret Smith (Maggie)
```

## `Greatest`

#### `class Greatest(*expressions, **extra)`

> **New in Django 1.9**

Accepte une liste d’au moins deux noms de champ ou expressions et renvoie la plus grande valeur. Chaque paramètre doit être d’un type similaire ; si vous mélangez des textes et des nombres, la base de données produira une erreur.

Exemple d’utilisation :

```
class Blog(models.Model):
    body = models.TextField()
    modified = models.DateTimeField(auto_now=True)

class Comment(models.Model):
    body = models.TextField()
    modified = models.DateTimeField(auto_now=True)
    blog = models.ForeignKey(Blog, on_delete=models.CASCADE)

>>> from django.db.models.functions import Greatest
>>> blog = Blog.objects.create(body='Greatest is the best.')
>>> comment = Comment.objects.create(body='No, Least is better.', blog=blog)
>>> comments = Comment.objects.annotate(last_updated=Greatest('modified', 'blog__modified'))
>>> annotated_comment = comments.get()
```

`annotated_comment.last_updated` sera la valeur la plus récente entre `blog.modified` et `comment.modified`.

> **Warning**
>
> Le comportement de `Greatest` varie entre les bases de données lorsqu’une ou plusieurs des expressions ont la valeur `null`:
>
> - PostgreSQL : `Greatest` renvoie l’expression non nulle la plus grande, ou `null` si toutes les expressions valent `null`.
> - SQLite, Oracle et MySQL : si l’une des expressions vaut `null`, `Greatest` renvoie `null`.
>
> Le comportement de PostgreSQL peut être émulé à l’aide de `Coalesce` si vous avez une valeur minimum adéquate à fournir comme valeur par défaut.

## `Least`

#### `class Least(*expressions, **extra)`

> **New in Django 1.9**

Accepte une liste d’au moins deux noms de champ ou expressions et renvoie la plus petite valeur. Chaque paramètre doit être d’un type similaire ; si vous mélangez des textes et des nombres, la base de données produira une erreur.

> **Warning**
>
> Le comportement de `Least` varie entre les bases de données lorsqu’une ou plusieurs des expressions ont la valeur `null`:
>
> - PostgreSQL : `Least` renvoie l’expression non nulle la plus petite, ou `null` si toutes les expressions valent `null`.
> - SQLite, Oracle et MySQL : si l’une des expressions vaut `null`, `Least` renvoie `null`.
>
> Le comportement de PostgreSQL peut être émulé à l’aide de `Coalesce` si vous avez une valeur maximum adéquate à fournir comme valeur par défaut.

## `Length`

#### `class Length(expression, **extra)`

Accepte un champ texte ou une expression unique et renvoie le nombre de caractères de la valeur. Si l’expression est nulle, la longueur renvoyée sera également nulle.

Exemple d’utilisation :

```
>>> # Get the length of the name and goes_by fields
>>> from django.db.models.functions import Length
>>> Author.objects.create(name='Margaret Smith')
>>> author = Author.objects.annotate(
...    name_length=Length('name'),
...    goes_by_length=Length('goes_by')).get()
>>> print(author.name_length, author.goes_by_length)
(14, None)
```

Cette expression peut aussi être inscrite comme transformation. Par exemple :

```
>>> from django.db.models import CharField
>>> from django.db.models.functions import Length
>>> CharField.register_lookup(Length, 'length')
>>> # Get authors whose name is longer than 7 characters
>>> authors = Author.objects.filter(name__length__gt=7)
```

> **Changed in Django 1.9**
>
> La possibilité d’inscrire la fonction en tant que transformation a été ajoutée.

## `Lower`

#### `class Lower(expression, **extra)`

Accepte un champ texte ou une expression unique et renvoie sa représentation en minuscules.

Cette expression peut aussi être inscrite comme transformation comme expliqué pour [`Length`](#django.db.models.functions.Length).

Exemple d’utilisation :

```
>>> from django.db.models.functions import Lower
>>> Author.objects.create(name='Margaret Smith')
>>> author = Author.objects.annotate(name_lower=Lower('name')).get()
>>> print(author.name_lower)
margaret smith
```

> **Changed in Django 1.9**
>
> La possibilité d’inscrire la fonction en tant que transformation a été ajoutée.

## `Now`

#### `class Now`

> **New in Django 1.9**

Renvoie la date et l’heure courante du serveur de base de données au moment où la requête est exécutée, typiquement en utilisant le code SQL `CURRENT_TIMESTAMP`.

Exemple d’utilisation :

```
>>> from django.db.models.functions import Now
>>> Article.objects.filter(published__lte=Now())
<QuerySet [<Article: How to Django>]>
```

> **Considérations sur PostgreSQL**
>
> Avec PostgreSQL, l’instruction `CURRENT_TIMESTAMP` renvoie l’heure du début de la transaction actuelle. Par conséquent, pour garantir la compatibilité entre bases de données, `Now()` utilise `STATEMENT_TIMESTAMP` à la place. Si vous avez besoin de l’horodatage de la transaction, utilisez [`django.contrib.postgres.functions.TransactionNow`](/fr/1.10/ref/contrib/postgres/functions/#django.contrib.postgres.functions.TransactionNow).

## `Substr`

#### `class Substr(expression, pos, length=None, **extra)`

Renvoie une sous-chaîne de longueur `length` extraite du champ ou de l’expression à partir de la position `pos`. L’indice de position commence à 1, il doit donc être plus grand que 0. Si `length` vaut `None`, tout le reste de la chaîne est renvoyé comme résultat.

Exemple d’utilisation :

```
>>> # Set the alias to the first 5 characters of the name as lowercase
>>> from django.db.models.functions import Substr, Lower
>>> Author.objects.create(name='Margaret Smith')
>>> Author.objects.update(alias=Lower(Substr('name', 1, 5)))
1
>>> print(Author.objects.get(name='Margaret Smith').alias)
marga
```

## `Upper`

#### `class Upper(expression, **extra)`

Accepte un champ texte ou une expression unique et renvoie sa représentation en majuscules.

Cette expression peut aussi être inscrite comme transformation comme expliqué pour [`Length`](#django.db.models.functions.Length).

Exemple d’utilisation :

```
>>> from django.db.models.functions import Upper
>>> Author.objects.create(name='Margaret Smith')
>>> author = Author.objects.annotate(name_upper=Upper('name')).get()
>>> print(author.name_upper)
MARGARET SMITH
```

> **Changed in Django 1.9**
>
> La possibilité d’inscrire la fonction en tant que transformation a été ajoutée.

## Fonctions de date

> **New in Django 1.10**

Nous allons utiliser le modèle suivant dans les exemples de chaque fonction :

```
class Experiment(models.Model):
    start_datetime = models.DateTimeField()
    start_date = models.DateField(null=True, blank=True)
    end_datetime = models.DateTimeField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)
```

### `Extract`

#### `class Extract(expression, lookup_name=None, tzinfo=None, **extra)`

Extrait un composant de date sous forme de nombre.

Accepte une `expression` représentant un champ `DateField` ou `DateTimeField` ainsi qu’un nom d’expression `lookup_name`, et renvoie la partie de date référencée par `lookup_name` sous forme de champ `IntegerField`. Django utilise habituellement la fonction d’extraction des bases de données, il est donc possible d’utiliser n’importe quel nom `lookup_name` pris en charge par la base de données en cours. Il est possible de passer aussi une sous-classe de `tzinfo`, habituellement fournie par `pytz`, pour extraire une valeur dans un fuseau horaire spécifique.

Étant donnée la date/heure `2015-06-15 23:30:01.000321+00:00`, les valeurs `lookup_name` possibles renvoient :

- « year » (année) : 2015
- « month » (mois) : 6
- « day » (jour) : 15
- « week\_day » (jour de semaine) : 2
- « hour » (heure) : 23
- « minute »: 30
- « second »: 1

Si un fuseau horaire différent comme `Australia/Melbourne` est actif dans Django, la date/heure est convertie dans le fuseau avant que la valeur soit extraite. Le décalage horaire de Melbourne dans la date d’exemple ci-dessus est +10:00. Les valeurs renvoyées lorsque ce fuseau est actif seront les mêmes que ci-dessus, à l’exception de :

- « day »: 16
- « week\_day »: 3
- « hour »: 9

> **Valeurs week_day**
>
> L’extraction `week_day` est calculée différemment de la plupart des bases de données et des fonctions Python standards. Cette fonction renvoie `1` pour dimanche, `2` pour lundi, jusqu’à `7` pour samedi.
>
> Le calcul équivalent en Python est :
>
> ```
> >>> from datetime import datetime
> >>> dt = datetime(2015, 6, 15)
> >>> (dt.isoweekday() % 7) + 1
> 2
> ```

Chaque valeur `lookup_name` ci-dessus possède une sous-classe de `Extract` correspondante (énumérées ci-dessous) qui devrait être utilisée au lieu de l’équivalent plus bavard, c’est-à-dire `ExtractYear(...)` au lieu de `Extract(..., lookup_name='year')`.

Exemple d’utilisation :

```
>>> from datetime import datetime
>>> from django.db.models.functions import Extract
>>> start = datetime(2015, 6, 15)
>>> end = datetime(2015, 7, 2)
>>> Experiment.objects.create(
...    start_datetime=start, start_date=start.date(),
...    end_datetime=end, end_date=end.date())
>>> # Add the experiment start year as a field in the QuerySet.
>>> experiment = Experiment.objects.annotate(
...    start_year=Extract('start_datetime', 'year')).get()
>>> experiment.start_year
2015
>>> # How many experiments completed in the same year in which they started?
>>> Experiment.objects.filter(
...    start_datetime__year=Extract('end_datetime', 'year')).count()
1
```

#### Extractions `DateField`

#### `class ExtractYear(expression, tzinfo=None, **extra)`

#### `lookup_name = 'year'`

#### `class ExtractMonth(expression, tzinfo=None, **extra)`

#### `lookup_name = 'month'`

#### `class ExtractDay(expression, tzinfo=None, **extra)`

#### `lookup_name = 'day'`

#### `class ExtractWeekDay(expression, tzinfo=None, **extra)`

#### `lookup_name = 'week_day'`

Il s’agit d’équivalents logiques à `Extract('champ_date', lookup_name)`. Chaque classe est aussi une classe `Transform` inscrite pour les champs `DateField` et `DateTimeField` comme `__(lookup_name)`, par ex. `__year`.

Comme les champs `DateField` n’ont pas de composant d’heure, seules les sous-classes de `Extract` qui s’appliquent aux parties de date peuvent être utilisées avec `DateField`:

```
>>> from datetime import datetime
>>> from django.utils import timezone
>>> from django.db.models.functions import (
...    ExtractYear, ExtractMonth, ExtractDay, ExtractWeekDay
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
...    start_datetime=start_2015, start_date=start_2015.date(),
...    end_datetime=end_2015, end_date=end_2015.date())
>>> Experiment.objects.annotate(
...     year=ExtractYear('start_date'),
...     month=ExtractMonth('start_date'),
...     day=ExtractDay('start_date'),
...     weekday=ExtractWeekDay('start_date'),
... ).values('year', 'month', 'day', 'weekday').get(
...     end_date__year=ExtractYear('start_date'),
... )
{'year': 2015, 'month': 6, 'day': 15, 'weekday': 2}
```

#### Extractions `DateTimeField`

En plus de ce qui suit, toutes les extractions pour `DateField` énumérées ci-dessus peuvent aussi être utilisées pour `DateTimeField`.

#### `class ExtractHour(expression, tzinfo=None, **extra)`

#### `lookup_name = 'hour'`

#### `class ExtractMinute(expression, tzinfo=None, **extra)`

#### `lookup_name = 'minute'`

#### `class ExtractSecond(expression, tzinfo=None, **extra)`

#### `lookup_name = 'second'`

Il s’agit d’équivalents logiques à `Extract('champ_datetime', lookup_name)`. Chaque classe est aussi une classe `Transform` inscrite pour le champ `DateTimeField` comme `__(lookup_name)`, par ex. `__minute`.

Exemples `DateTimeField`:

```
>>> from datetime import datetime
>>> from django.utils import timezone
>>> from django.db.models.functions import (
...    ExtractYear, ExtractMonth, ExtractDay, ExtractWeekDay,
...    ExtractHour, ExtractMinute, ExtractSecond,
... )
>>> start_2015 = datetime(2015, 6, 15, 23, 30, 1, tzinfo=timezone.utc)
>>> end_2015 = datetime(2015, 6, 16, 13, 11, 27, tzinfo=timezone.utc)
>>> Experiment.objects.create(
...    start_datetime=start_2015, start_date=start_2015.date(),
...    end_datetime=end_2015, end_date=end_2015.date())
>>> Experiment.objects.annotate(
...     year=ExtractYear('start_datetime'),
...     month=ExtractMonth('start_datetime'),
...     day=ExtractDay('start_datetime'),
...     weekday=ExtractWeekDay('start_datetime'),
...     hour=ExtractHour('start_datetime'),
...     minute=ExtractMinute('start_datetime'),
...     second=ExtractSecond('start_datetime'),
... ).values(
...     'year', 'month', 'day', 'weekday', 'hour', 'minute', 'second',
... ).get(end_datetime__year=ExtractYear('start_datetime'))
{'year': 2015, 'month': 6, 'day': 15, 'weekday': 2, 'hour': 23, 'minute': 30, 'second': 1}
```

Lorsque [`USE_TZ`](/fr/1.10/ref/settings/#std-setting-USE_TZ) vaut `True`, les dates/heures sont stockées en UTC dans la base de données. Si un autre fuseau horaire est actif dans Django, la date/heure est convertie dans ce fuseau avant que la valeur soit extraite. L’exemple ci-dessous convertit dans le fuseau horaire de Melbourne (UTC +10:00), ce qui modifie les valeurs du jour, du jour de la semaine et de l’heure qui sont renvoyées :

```
>>> import pytz
>>> melb = pytz.timezone('Australia/Melbourne')  # UTC+10:00
>>> with timezone.override(melb):
...    Experiment.objects.annotate(
...        day=ExtractDay('start_datetime'),
...        weekday=ExtractWeekDay('start_datetime'),
...        hour=ExtractHour('start_datetime'),
...    ).values('day', 'weekday', 'hour').get(
...        end_datetime__year=ExtractYear('start_datetime'),
...    )
{'day': 16, 'weekday': 3, 'hour': 9}
```

Le passage explicite du fuseau horaire à la fonction `Extract` fonctionne de la même manière et prend la priorité sur le fuseau horaire actif :

```
>>> import pytz
>>> melb = pytz.timezone('Australia/Melbourne')
>>> Experiment.objects.annotate(
...     day=ExtractDay('start_datetime', tzinfo=melb),
...     weekday=ExtractWeekDay('start_datetime', tzinfo=melb),
...     hour=ExtractHour('start_datetime', tzinfo=melb),
... ).values('day', 'weekday', 'hour').get(
...     end_datetime__year=ExtractYear('start_datetime'),
... )
{'day': 16, 'weekday': 3, 'hour': 9}
```

### `Trunc`

#### `class Trunc(expression, kind, output_field=None, tzinfo=None, **extra)`

Tronque une date jusqu’à un composant significatif.

Lorsque vous ne voulez que savoir si quelque chose s’est produit durant une année, une heure ou un jour particulier, mais pas à quelle  seconde, `Trunc` (et ses sous-classes) peut être utile pour filtrer ou agréger vos données. Par exemple, vous pouvez utiliser `Trunc` pour calculer le nombre de ventes par jour.

`Trunc` accepte une seule `expression`, représentant un champ `DateField` ou `DateTimeField`, une variable `kind` représentant une partie de date et un champ `output_field` qui vaut `DateTimeField()` ou `DateField()`. Elle renvoie un date ou une date/heure en fonction de `output_field`, avec les champs jusqu’à `kind` définis à leur valeur minimale. Si `output_field` est omis, la valeur par défaut sera le type `output_field` de `expression`. Il est possible de passer aussi une sous-classe de `tzinfo`, habituellement fournie par `pytz`, pour tronquer une valeur dans un fuseau horaire spécifique.

Étant donnée la date/heure `2015-06-15 14:30:50.000321+00:00`, les valeurs `kind` possibles renvoient :

- « year »: 2015-01-01 00:00:00+00:00
- « month »: 2015-06-01 00:00:00+00:00
- « day »: 2015-06-15 00:00:00+00:00
- « hour »: 2015-06-15 14:00:00+00:00
- « minute »: 2015-06-15 14:30:00+00:00
- « second »: 2015-06-15 14:30:50+00:00

Si un fuseau horaire différent comme `Australia/Melbourne` est actif dans Django, la date/heure est convertie dans le nouveau fuseau avant que la valeur soit tronquée. Le décalage horaire de Melbourne dans la date d’exemple ci-dessus est +10:00. Les valeurs renvoyées lorsque ce fuseau est actif seront :

- « year »: 2015-01-01 00:00:00+11:00
- « month »: 2015-06-01 00:00:00+10:00
- « day »: 2015-06-16 00:00:00+10:00
- « hour »: 2015-06-16 00:00:00+10:00
- « minute »: 2015-06-16 00:30:00+10:00
- « second »: 2015-06-16 00:30:50+10:00

L’année présente un décalage de +11:00 parce que le résultat traverse un passage à l’heure d’été.

Chaque valeur `kind` ci-dessus possède une sous-classe de `Trunc` correspondante (énumérées ci-dessous) qui devrait être utilisée au lieu de l’équivalent plus bavard, c’est-à-dire `TruncYear(...)` au lieu de `Trunc(..., kind='year')`.

Les sous-classes sont toutes définies comme des transformations, mais elles ne sont inscrites pour aucun champ, car les noms de requête qui s’imposent sont déjà réservés par les sous-classes de `Extract`.

Exemple d’utilisation :

```
>>> from datetime import datetime
>>> from django.db.models import Count, DateTimeField
>>> from django.db.models.functions import Trunc
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 30, 50, 321))
>>> Experiment.objects.create(start_datetime=datetime(2015, 6, 15, 14, 40, 2, 123))
>>> Experiment.objects.create(start_datetime=datetime(2015, 12, 25, 10, 5, 27, 999))
>>> experiments_per_day = Experiment.objects.annotate(
...    start_day=Trunc('start_datetime', 'day', output_field=DateTimeField())
... ).values('start_day').annotate(experiments=Count('id'))
>>> for exp in experiments_per_day:
...     print(exp['start_day'], exp['experiments'])
...
2015-06-15 00:00:00 2
2015-12-25 00:00:00 1
>>> experiments = Experiment.objects.annotate(
...    start_day=Trunc('start_datetime', 'day', output_field=DateTimeField())
... ).filter(start_day=datetime(2015, 6, 15))
>>> for exp in experiments:
...     print(exp.start_datetime)
...
2015-06-15 14:30:50.000321
2015-06-15 14:40:02.000123
```

#### Troncature de `DateField`

#### `class TruncYear(expression, output_field=None, tzinfo=None, **extra)`

#### `kind = 'year'`

#### `class TruncMonth(expression, output_field=None, tzinfo=None, **extra)`

#### `kind = 'month'`

Ce sont des équivalences logiques à `Trunc('champ_date', kind)`. Elles tronquent toutes les parties de la date jusqu’à `kind`, ce qui permet de grouper ou de filtrer des dates avec une plus faible précision. `expression` peut avoir une valeur `output_field` de `DateField` ou de `DateTimeField`.

Comme les champs `DateField` n’ont pas de composant d’heure, seules les sous-classes de `Trunc` qui s’appliquent aux parties de date peuvent être utilisées avec `DateField`:

```
>>> from datetime import datetime
>>> from django.db.models import Count
>>> from django.db.models.functions import TruncMonth, TruncYear
>>> from django.utils import timezone
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> start2 = datetime(2015, 6, 15, 14, 40, 2, 123, tzinfo=timezone.utc)
>>> start3 = datetime(2015, 12, 31, 17, 5, 27, 999, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> Experiment.objects.create(start_datetime=start2, start_date=start2.date())
>>> Experiment.objects.create(start_datetime=start3, start_date=start3.date())
>>> experiments_per_year = Experiment.objects.annotate(
...    year=TruncYear('start_date')).values('year').annotate(
...    experiments=Count('id'))
>>> for exp in experiments_per_year:
...     print(exp['year'], exp['experiments'])
...
2014-01-01 1
2015-01-01 2

>>> import pytz
>>> melb = pytz.timezone('Australia/Melbourne')
>>> experiments_per_month = Experiment.objects.annotate(
...    month=TruncMonth('start_datetime', tzinfo=melb)).values('month').annotate(
...    experiments=Count('id'))
>>> for exp in experiments_per_month:
...     print(exp['month'], exp['experiments'])
...
2015-06-01 00:00:00+10:00 1
2016-01-01 00:00:00+11:00 1
2014-06-01 00:00:00+10:00 1
```

#### Troncature de `DateTimeField`

#### `class TruncDate(expression, **extra)`

#### `lookup_name = 'date'`

#### `output_field = DateField()`

`TruncDate` force le type de `expression` à une date plutôt que d’utiliser l’instruction SQL de troncature. Elle est aussi inscrite comme transformation pour `DateTimeField` sous la forme `__date`.

#### `class TruncDay(expression, output_field=None, tzinfo=None, **extra)`

#### `kind = 'day'`

#### `class TruncHour(expression, output_field=None, tzinfo=None, **extra)`

#### `kind = 'hour'`

#### `class TruncMinute(expression, output_field=None, tzinfo=None, **extra)`

#### `kind = 'minute'`

#### `class TruncSecond(expression, output_field=None, tzinfo=None, **extra)`

#### `kind = 'second'`

Ce sont des équivalences logiques à `Trunc('champ_dateheure', kind)`. Elles tronquent toutes les parties de la date jusqu’à `kind`, ce qui permet de grouper ou de filtrer des dates/heures avec une plus faible précision. `expression` doit avoir une valeur `output_field` de `DateTimeField`.

Exemple d’utilisation :

```
>>> from datetime import date, datetime
>>> from django.db.models import Count
>>> from django.db.models.functions import (
...     TruncDate, TruncDay, TruncHour, TruncMinute, TruncSecond,
... )
>>> from django.utils import timezone
>>> import pytz
>>> start1 = datetime(2014, 6, 15, 14, 30, 50, 321, tzinfo=timezone.utc)
>>> Experiment.objects.create(start_datetime=start1, start_date=start1.date())
>>> melb = pytz.timezone('Australia/Melbourne')
>>> Experiment.objects.annotate(
...     date=TruncDate('start_datetime'),
...     day=TruncDay('start_datetime', tzinfo=melb),
...     hour=TruncHour('start_datetime', tzinfo=melb),
...     minute=TruncMinute('start_datetime'),
...     second=TruncSecond('start_datetime'),
... ).values('date', 'day', 'hour', 'minute', 'second').get()
{'date': datetime.date(2014, 6, 15),
 'day': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
 'hour': datetime.datetime(2014, 6, 16, 0, 0, tzinfo=<DstTzInfo 'Australia/Melbourne' AEST+10:00:00 STD>),
 'minute': 'minute': datetime.datetime(2014, 6, 15, 14, 30, tzinfo=<UTC>),
 'second': datetime.datetime(2014, 6, 15, 14, 30, 50, tzinfo=<UTC>)
}
```
