# Documentation Django 5.2.8

# Notes de publication de Django 4.0

7 décembre 2021

Bienvenue dans Django 4.0 !

Ces notes de publications couvrent les nouvelles fonctionnalités, ainsi que certaines modifications non rétrocompatibles dont il faut être au courant lors de la mise à jour depuis Django 3.2 ou des versions plus anciennes. Nous avons commencé le processus d’obsolescence de certaines fonctionnalités.

Voir le guide Mise à jour de Django à une version plus récente si vous mettez à jour un projet existant.

## Compatibilité Python

Django 4.0 requiert Python 3.8, 3.9 ou 3.10. Nous recommandons vivement et nous ne prenons officiellement en charge que la dernière publication de chaque série.

La série Django 3.2.x est la dernière à prendre en charge Python 3.6 et 3.7.

## Quoi de neuf dans Django 4.0

### Implémentation des fuseaux horaires par défaut avec `zoneinfo`

Le module `zoneinfo` de la bibliothèque Python standard est dorénavant l’implémentation par défaut des fuseaux horaires dans Django.

Il s’agit de l’étape suivante de la migration depuis `pytz` à `zoneinfo`. Django 3.2 autorisait l’utilisation de fuseaux horaires autres que `pytz`. Django 4.0 fait de `zoneinfo` l’implémentation par défaut. La prise en charge de `pytz` est maintenant obsolète et sera supprimée dans Django 5.0.

`zoneinfo` fait partie de la bibliothèque standard de Python à partir de la version 3.9. Le paquet `backports.zoneinfo` est automatiquement installé avec Django si vous utilisez encore Python 3.8.

Le passage à `zoneinfo` devrait être largement transparent. La sélection du fuseau horaire actuel, la conversion d’instances de dates vers le fuseau horaire actuel dans les formulaires et gabarits, de même que les opérations sur les dates conscientes en UTC ne sont pas touchées.

Cependant, si vous travaillez avec des fuseaux horaires autres que UTC et que vous utilisez les API `pytz` `normalize()` et `localize()`, possiblement avec le réglage `TIME_ZONE`, il faudra auditer votre code, car `pytz` et `zoneinfo` ne sont pas complètement équivalentes.

Pour vous donner du temps pour un tel audit, le réglage temporaire `USE_DEPRECATED_PYTZ` permet de continuer à utiliser `pytz` durant le cycle de publication 4.x. Ce réglage sera supprimé dans Django 5.0.

De plus, un paquet pytz_deprecation_shim, créé par l’auteur de `zoneinfo`, peut aider à la migration à partir de `pytz`. Ce paquet fournit des fonctions de substitution pour vous aider à vous séparer de `pytz` et contient un guide de migration détaillé vous expliquant comment passer à la nouvelle API de `zoneinfo`.

Using pytz_deprecation_shim and the `USE_DEPRECATED_PYTZ` transitional setting is recommended if you need a gradual update path.

### Contraintes d’unicité basées sur des fonctions

Le nouveau paramètre positionnel `*expressions` de `UniqueConstraint()` permet de créer des contraintes d’unicité fonctionnelles sur la base d’expressions et de fonctions de base de données. Par exemple

    from django.db import models
    from django.db.models import UniqueConstraint
    from django.db.models.functions import Lower

    class MyModel(models.Model):
        first_name = models.CharField(max_length=255)
        last_name = models.CharField(max_length=255)

        class Meta:
            constraints = [
                UniqueConstraint(
                    Lower("first_name"),
                    Lower("last_name").desc(),
                    name="first_last_name_unique",
                ),
            ]

Les contraintes d’unicité fonctionnelles peuvent être ajoutés aux modèles en utilisant l’option `Meta.constraints`.

### Hacheur de mot de passe `scrypt`

Le nouveau hacheur de mot de passe scrypt est plus sûr et préféré à PBKDF2. Cependant, ce n’est pas le choix par défaut car il nécessite OpenSSL 1.1+ et plus de mémoire.

### Moteur de cache Redis

The new `django.core.cache.backends.redis.RedisCache` cache backend provides built-in support for caching with Redis. redis-py 3.0.0 or higher is required. For more details, see the documentation on caching with Redis in Django.

### Rendu des formulaires basé sur des gabarits

`Forms`, Formsets et `ErrorList` sont dorénavant produits avec le moteur de gabarits pour faciliter la personnalisation. Pour les formulaires `Form`, référez-vous aux nouveautés `render()`, `get_context()` et `template_name`, alors que pour les jeux de formulaires `Formset`, consultez rendu des jeux de formulaires.

### Fonctionnalités mineures

#### `django.contrib.admin`

- Le gabarit `admin/base.html` possède dorénavant un nouveau bloc `header` (en-tête) qui contient l’en-tête du site d’administration.

- La nouvelle méthode `ModelAdmin.get_formset_kwargs()` permet de personnaliser les arguments mot-clés transmis au constructeur d’un jeu de formulaires.

- La barre latérale de navigation possède maintenant une barre d’outils de filtre rapide.

- La nouvelle variable de contexte `model` contenant la classe de modèle de chaque modèle a été ajoutée à la méthode `AdminSite.each_context()`.

- Le nouvel attribut `ModelAdmin.search_help_text` permet d’indiquer un texte descriptif pour la zone de recherche.

- Quand l’attribut `InlineModelAdmin.verbose_name_plural` est manquant, son contenu se base dorénavant sur `InlineModelAdmin.verbose_name` + `'s'`.

- La version intégrée de jQuery a été mise à jour de 3.5.1 vers 3.6.0.

#### `django.contrib.admindocs`

- `admindocs` permet dorénavant des configurations spéciales où `ROOT_URLCONF` n’est pas une chaîne.

- La section des modèles de `admindocs` affiche maintenant aussi les propriétés en cache.

#### `django.contrib.auth`

- Le nombre d’itération par défaut du hacheur de mot de passe PBKDF2 a été augmenté de 260’000 à 320’000.

- Le nouvel attribut `LoginView.next_page` et la méthode `get_default_redirect_url()` permettent de personnaliser la redirection après la connexion.

#### `django.contrib.gis`

- La prise en charge de SpatiaLite 5 a été ajoutée.

- `GDALRaster` permet dorénavant de créer des matrices dans n’importe quel système de fichiers virtuel GDAL.

- La nouvelle classe `GISModelAdmin` permet de personnaliser le composant utilisé pour les champs `GeometryField`. C’est l’utilisation recommandée, dans la mesure où `GeoModelAdmin` et `OSMGeoAdmin` ont été rendues obsolètes.

#### `django.contrib.postgres`

- Le moteur PostgreSQL prend dorénavant en charge la connexion par un nom de service. Voir Paramètres de connexion PostgreSQL pour plus de détails.

- La nouvelle opération `AddConstraintNotValid` permet de créer des contraintes d’intégrité avec PostgreSQL sans vérifier que toutes les lignes existantes satisfont la nouvelle contrainte.

- La nouvelle opération `ValidateConstraint` permet de valider les contraintes d’intégrité qui ont été créées avec `AddConstraintNotValid` sur PostgreSQL.

- La nouvelle expression `ArraySubquery()` permet de définir des sous-requêtes pour construire des listes de valeurs avec PostgreSQL.

- La nouvelle expression de requête `trigram_word_similar` et les expressions `TrigramWordDistance()` et `TrigramWordSimilarity()` permettent d’utiliser la similarité de mots par trigramme.

#### `django.contrib.staticfiles`

- `ManifestStaticFilesStorage` remplace dorénavant les chemins vers les références JavaScript « source map » par leur équivalent avec empreinte intégrée.

- Le nouvel argument `manifest_storage` de `ManifestFilesMixin` et de `ManifestStaticFilesStorage` permet de personnaliser le stockage du fichier « manifest ».

#### Cache

- La nouvelle API asynchrone de `django.core.cache.backends.base.BaseCache` débute le processus de compatibilité asynchrone des moteurs de cache. Lea nouvelles méthodes asynchrones sont toutes préfixées par `a`, par ex. `aadd()`, `aget()`, `aset()`, `aget_or_set()` ou `adelete_many()`.

  À l’avenir, le préfixe `a` sera utilisé de manière générale pour les variantes asynchrones des méthodes.

#### CSRF

- La protection CSRF consulte dorénavant l’en-tête `Origin` quand elle existe. Pour faciliter cela, certaines modifications du réglage `CSRF_TRUSTED_ORIGINS` sont nécessaires.

#### Formulaires

- `ModelChoiceField` inclut dorénavant la valeur fournie dans l’argument `params` d’une erreur `ValidationError` pour le message d’erreur `invalid_choice`. Cela permet à des messages d’erreur personnalisés d’utiliser le substituant `%(value)s`.

- `BaseFormSet` produit dorénavant les erreurs non liées à un champ avec une classe supplémentaire `nonform` pour aider à les distinguer des erreurs spécifiques à un champ particulier.

- `BaseFormSet` permet maintenant de contrôler le composant utilisé pour la suppression des formulaires avec `can_delete` en définissant l’attribut `deletion_widget` ou en surchargeant la méthode `get_deletion_widget()`.

#### Internationalisation

- La prise en charge des traductions en malais a été ajoutée.

#### Vues génériques

- `DeleteView` utilise dorénavant `FormMixin`, permettant d’ajouter par exemple à une sous-classe de `Form` une case à cocher pour confirmer sa suppression. De plus, cela permet à `DeleteView` de fonctionner correctement avec `django.contrib.messages.views.SuccessMessageMixin`.

  En accord avec le fonctionnement de `FormMixin`, la suppression d’objets par les requêtes POST est traitée dans `form_valid()`. Les logiques personnalisées de suppression dans les méthodes `delete()` surchargées doivent être déplacées dans `form_valid()` ou dans une méthode utilitaire partagée, selon les cas.

#### Journalisation

- L’alias de la base de données utilisée dans un appel SQL est dorénavant transmise comme contexte supplémentaire avec chaque message du journaliseur django.db.backends.

#### Commandes d’administration

- La commande d’administration `runserver` prend désormais en charge l’option `--skip-checks`.

- Avec PostgreSQL, `dbshell` accepte dorénavant un fichier de mot de passe en paramètre.

- The `shell` command now respects `sys.__interactivehook__` at startup. This allows loading shell history between interactive sessions. As a consequence, `readline` is no longer loaded if running in isolated mode.

- Le nouvel attribut `BaseCommand.suppressed_base_arguments` permet de supprimer des options de commande par défaut non prises en charge dans le contenu de l’aide.

- Les nouvelles options `startapp --exclude` et `startproject --exclude` permettent d’exclure des répertoires des modèles.

#### Modèles

- La nouvelle méthode `QuerySet.contains(obj)` indique si le jeu de requête contient l’objet donné. La requête est effectuée de la manière la plus simple et rapide possible.

- Le nouvel argument `precision` de la fonction de base de données `Round()` permet de définir le nombre de décimales à conserver pour l’arrondi.

- `QuerySet.bulk_create()` définit dorénavant la clé primaire des objets quand on l’utilise avec SQLite 3.35+.

- Le champ `DurationField` prend désormais en charge la multiplication et la division par des valeurs scalaires avec SQLite.

- `QuerySet.bulk_update()` renvoie dorénavant le nombre d’objets mis à jour.

- Le nouvel attribut `Expression.empty_result_set_value` permet de définir une valeur à renvoyer lorsque la fonction est appliquée à un jeu de résultat vide.

- The `skip_locked` argument of `QuerySet.select_for_update()` is now allowed on MariaDB 10.6+.

- Les expressions `Lookup` peuvent maintenant être utilisées dans les annotations, les agrégats et directement dans les filtres des requêtes `QuerySet`.

- Le nouvel argument default des agrégats intégrés permet de définir une valeur à renvoyer lorsque le jeu de requête (ou le groupement) ne contient aucune ligne, à la place de `None`.

#### Requêtes et réponses

- L’intergiciel `SecurityMiddleware` ajoute dorénavant l’en-tête ref:Cross-Origin Opener Policy <cross-origin-opener-policy> avec une valeur de `'same-origin'` pour empêcher les fenêtres popup d’origine croisée de partager le même contexte de navigation. Vous pouvez empêcher l’ajout de cet en-tête en définissant le réglage `SECURE_CROSS_ORIGIN_OPENER_POLICY` à `None`.

#### Signaux

- The new `stdout` argument for `pre_migrate()` and `post_migrate()` signals allows redirecting output to a stream-like object. It should be preferred over `sys.stdout` and `print()` when emitting verbose output in order to allow proper capture when testing.

#### Gabarits

- Le filtre de gabarit `floatformat` permet dorénavant d’utiliser le suffixe `u` pour forcer la désactivation de la régionalisation.

#### Tests

- Le nouvel argument `serialized_aliases` de `django.test.utils.setup_databases()` détermine quels alias de tests de bases de données `DATABASES` doivent voir leur état sérialisé pour permettre l’utilisation de la fonctionnalité serialized_rollback.

- The `test --buffer` option now supports parallel tests.

- The new `logger` argument to `DiscoverRunner` allows a Python logger to be used for logging.

- La nouvelle méthode `DiscoverRunner.log()` fournit une façon de journaliser les messages en utilisant `DiscoverRunner.logger` ou en affichant dans la console si cette dernière n’est pas définie.

- `DiscoverRunner` can now execute tests in a random order using the `test --shuffle` option.

- L’option `test --parallel` prend dorénavant en charge la valeur `auto` pour lancer un processus de tests pour chaque cœur de processeur.

- `TestCase.captureOnCommitCallbacks()` capture dorénavant les nouvelles fonctions de rappel ajoutées lors de l’exécution des fonctions de rappel `transaction.on_commit()`.

## Changements incompatibles avec les anciennes versions dans Django 4.0

### API de moteur de base de données

Cette section décrit des modifications qui pourraient être nécessaires dans des moteurs de base de données tiers.

- Les méthodes `DatabaseOperations.year_lookup_bounds_for_date_field()` et `year_lookup_bounds_for_datetime_field()` acceptent désormais l’argument facultatif `iso_year` afin de prendre en charge les limites pour les années de numérotation de semaines ISO-8601.

- Le deuxième argument des méthodes `DatabaseSchemaEditor._unique_sql()` et `_create_unique_sql()` s’appelle maintenant `fields` au lieu de `columns`.

### `django.contrib.gis`

- La prise en charge de PostGIS 2.3 a été supprimée.

- La prise en charge de GDAL 2.0 et GEOS 3.5 a été supprimée.

### Abandon de la prise en charge de PostgreSQL 9.6

La prise en charge amont de PostgreSQL 9.6 se termine en novembre 2021. Django 4.0 prend en charge PostgreSQL 10 et plus récent.

De plus, la version minimale prise en charge de `psycopg2` est passée de 2.5.4 à 2.8.4, car `psycopg2` 2.8.4 est la première version à prendre en charge Python 3.8.

### Abandon de la prise en charge de Oracle 12.2 et 18c

La prise en charge de Oracle 12.2 par le projet amont se termine en mars 2022 et en juin 2021 pour Orcale 18c. Django 3.2 sera pris en charge jusqu’en avril 2024. Django 4.0 prend officiellement en charge Oracle 19c.

### Modifications de `CSRF_TRUSTED_ORIGINS`

#### Modification de format

Les valeurs dans le réglage `CSRF_TRUSTED_ORIGINS` doivent inclure le protocole (par ex. `'http://'` ou `'https://'`) et non plus uniquement le nom d’hôte.

De même, les valeurs qui commencent par un point doivent dorénavant aussi inclure un astérisque avant le point. Par exemple, changez `'.exemple.com'` en `'https://*.exemple.com'`.

Un contrôle système détecte les changements nécessaires.

#### Sa configuration peut maintenant être requise

Comme la protection CSRF consulte maintenant l’en-tête `Origin`, il se peut que vous deviez définir `CSRF_TRUSTED_ORIGINS`, particulièrement si vous autorisez les requêtes à partir de sous-domaines en définissant `CSRF_COOKIE_DOMAIN` (ou `SESSION_COOKIE_DOMAIN` si `CSRF_USE_SESSIONS` est activé) à une valeur commençant par un point.

### `SecurityMiddleware` ne définit plus l’en-tête `X-XSS-Protection`

L’intergiciel `SecurityMiddleware` ne définit plus l’en-tête `X-XSS-Protection` quand le réglage `SECURE_BROWSER_XSS_FILTER` vaut `True`. Ce réglage est supprimé.

La plupart des navigateurs modernes ne considèrent plus l’en-tête HTTP `X-XSS-Protection`. Vous pouvez utiliser plutôt Content-Security-Policy sans autoriser les scripts `'unsafe-inline'`.

Si vous souhaitez prendre en charge les anciens navigateurs et définir cet en-tête, utilisez cette ligne dans un intergiciel personnalisé

    response.headers.setdefault("X-XSS-Protection", "1; mode=block")

### Modifications de l’autodétecteur de migrations

L’autodétecteur de migrations utilise dorénavant les états de modèles au lieu de classes de modèles. De plus, les opérations de migration pour les champs `ForeignKey` et `ManyToManyField` ne définissent plus les attributs qui n’ont pas été transmis à ces champs lors de leur initialisation.

Comme effet de bord, le lancement de `makemigrations` pourrait générer des opérations `AlterField` neutres pour les champs `ManyToManyField` et `ForeignKey` dans certains cas.

### Modifications de `DeleteView`

`DeleteView` utilise dorénavant `FormMixin` pour gérer les requêtes `POST`. En conséquence, tout logique personnalisée de suppression dans les méthodes `delete()` doivent être déplacées dans `form_valid()`, ou dans une autre méthode utilitaire partagée, si nécessaire.

### Table and column naming scheme changes on Oracle

Django 4.0 inadvertently changed the table and column naming scheme on Oracle. This causes errors for models and fields with names longer than 30 characters. Unfortunately, renaming some Oracle tables and columns is required. Use the upgrade script in 33789 to generate `RENAME` statements to change naming scheme.

### Divers

- La prise en charge de `cx_Oracle` < 7.0 a été abandonnée.

- Pour permettre de servir un site Django sur un sous-chemin sans modifier la valeur de `STATIC_URL`, la barre oblique initiale est supprimée de ce réglage (dorénavant `'static/'`) dans le gabarit `startproject` par défaut.

- La méthode `AdminSite` pour la vue `index` du site d’administration n’est plus décorée par `never_cache` lorsqu’on y accède directement, sans passer par la propriété recommandée `AdminSite.urls` ou par la méthode `AdminSite.get_urls()`.

- Les opérations non prises en charge d’un jeu de requête segmenté produisent une erreur `TypeError` au lieu de `AssertionError`.

- La fonction non documentée `django.test.runner.reorder_suite()` a été renommée en `reorder_tests()`. Elle accepte dorénavant une structure itérable de tests plutôt qu’une suite de tests, et renvoie un itérateur de tests.

- L’appel à `FileSystemStorage.delete()` avec un paramètre `name` vide produit maintenant une exception `ValueError` au lieu de `AssertionError`.

- L’appel à `EmailMultiAlternatives.attach_alternative()` ou `EmailMessage.attach()` avec des valeurs de paramètres `content` ou `mimetype` non valables produisent maintenant une exception `ValueError` au lieu de `AssertionError`.

- `assertHTMLEqual()` ne considère plus un attribut non booléen sans valeur comme égal à un attribut avec les mêmes nom et valeur.

- Les tests dont le chargement échoue, par exemple en raison d’erreurs de syntaxe, correspondent maintenant toujours lorsqu’on utilise l’option `test --tag`.

- La fonction non documentée `django.contrib.admin.utils.lookup_needs_distinct()` a été renommée en `lookup_spawns_duplicates()`.

- La méthode non documentée `HttpRequest.get_raw_uri()` a été supprimée. La méthode `HttpRequest.build_absolute_uri()` pourrait être une alternative appropriée.

- L’argument `object` des méthodes non documentées `ModelAdmin.log_addition()`, `log_change()` et `log_deletion()` a été renommé en `obj`.

- `RssFeed`, `Atom1Feed` et leurs sous-classes émettent désormais les éléments sans contenu sous forme de balises autofermées.

- `NodeList.render()` ne force plus le résultat de la méthode `render()` pour les nœuds individuels à des chaînes. `Node.render()` doit toujours renvoyer une chaîne comme sa documentation le demande.

- La propriété `where_class` de `django.db.models.sql.query.Query` ainsi que l’argument `where_class` de la méthode privée `get_extra_restriction()` de `ForeignObject` et `ForeignObjectRel` sont supprimées. Si nécessaire, initialisez un nœud `django.db.models.sql.where.WhereNode` à la place.

- L’argument `filter_clause` de la méthode non documentée `Query.add_filter()` a été remplacé par deux arguments positionnels `filter_lhs` et `filter_rhs`.

- `CsrfViewMiddleware` utilise dorénavant `request.META['CSRF_COOKIE_NEEDS_UPDATE']` en lieu et place de `request.META['CSRF_COOKIE_USED']`, `request.csrf_cookie_needs_reset` et `response.csrf_cookie_set` pour détecter si le cookie CSRF doit être envoyé. Il s’agit d’une API privée et non documentée.

- La constante non documentée `TRANSLATOR_COMMENT_MARK` a été déplacée de `django.template.base` vers `django.utils.translation.template`.

- L’argument `real_apps` de la méthode non documentée `django.db.migrations.state.ProjectState.__init__()` doit dorénavant être un ensemble `set` quand il est défini.

- Les composants `RadioSelect` et `CheckboxSelectMultiple` sont dorénavant produits dans des balises `<div>` pour qu’ils soient annoncés de manière plus concise par les lecteurs d’écran. Si vous voulez revenir au comportement précédent, surchargez le gabarit du composant par le gabarit qui était utilisé dans Django 3.2.

- Le filtre de gabarit `floatformat` ne dépend plus du réglage `USE_L10N` et renvoie toujours un résultat régionalisé. Utilisez le suffixe `u` pour désactiver la régionalisation.

- La valeur par défaut du réglage `USE_L10N` est dorénavant `True`. Consultez la section sur la régionalisation ci-dessus pour plus de détails.

- As part of the move to zoneinfo, `django.utils.timezone.utc` is changed to alias `datetime.timezone.utc`.

- La version minimum de `asgiref` prise en charge est passée de 3.3.2 à 3.4.1.

## Fonctionnalités rendues obsolètes dans Django 4.0

### Utilisation des fuseaux horaires `pytz`

Dans le contexte du passage à zoneinfo, l’utilisation des fuseaux horaires `pytz` est obsolète.

En conséquence, les arguments `is_dst` des éléments suivants sont aussi obsolètes :

- `django.db.models.query.QuerySet.datetimes()`

- `django.db.models.functions.Trunc()`

- `django.db.models.functions.TruncSecond()`

- `django.db.models.functions.TruncMinute()`

- `django.db.models.functions.TruncHour()`

- `django.db.models.functions.TruncDay()`

- `django.db.models.functions.TruncWeek()`

- `django.db.models.functions.TruncMonth()`

- `django.db.models.functions.TruncQuarter()`

- `django.db.models.functions.TruncYear()`

- `django.utils.timezone.make_aware()`

La prise en charge de `pytz` sera supprimée dans Django 5.0.

### Prise en charge des fuseaux horaires

Afin de respecter les bonnes pratiques, la valeur par défaut du réglage `USE_TZ` a été modifiée de `False` à `True`, et la prise en charge des fuseaux horaires sera activée par défaut dans Django 5.0.

Notez que le fichier `settings.py` créé par défaut par `django-admin startproject` définit `USE_TZ = True` depuis Django 1.4.

Dans l’intervalle, vous pouvez définir `USE_TZ` à `False` dans vos réglages de projet si vous n’en voulez pas.

### Régionalisation

Afin de respecter les bonnes pratiques, la valeur par défaut du réglage `USE_L10N` a été modifiée de `False` à `True`.

De plus, `USE_L10N` est obsolète à partir de cette version. Dès Django 5.0, les dates et les nombres seront affichés par défaut en fonction de la langue active.

Django continue d’appliquer la balise `{% localize %}` et les filtres `localize`/ `unlocalize`.

### Divers

- Le réglage de test `SERIALIZE` est obsolète car il peut être déduit de `databases` avec l’option serialized_rollback activée.

- Le module non documenté `django.utils.baseconv` est obsolète.

- Le module non documenté `django.utils.datetime_safe` est obsolète.

- Le protocole par défaut pour les plans de site construits en dehors du contexte de la requête changera de `'http'` à `'https'` dans Django 5.0.

- L’argument `extra_tests` de `DiscoverRunner.build_suite()` et de `DiscoverRunner.run_tests()` est obsolète.

- Dans Django 5.0, les agrégats `ArrayAgg`, `JSONBAgg` et `StringAgg` renverront `None` lorsqu’il n’y a aucune ligne au lieu de respectivement `[]`, `[]` et `''`. Si vous avez besoin du comportement précédent, définissez explicitement l’argument `default` à `Value([])`, `Value('[]')` ou `Value('')`.

- Les classes `django.contrib.gis.admin.GeoModelAdmin` et `OSMGeoAdmin` sont obsolètes, Utilisez à la place `ModelAdmin` ou `GISModelAdmin`.

- Comme le rendu des formulaires utilise dorénavant le moteur de gabarits, la méthode utilitaire et non documentée `BaseForm._html_output()` est obsolète.

- La possibilité de renvoyer une chaîne `str` à partir de `ErrorList` et `ErrorDict` est obsolète. Il est attendu que ces méthodes renvoient un objet `SafeString`.

## Fonctionnalités supprimées dans 4.0

Ces fonctionnalités ont atteint la fin de leur cycle d’obsolescence et sont supprimées dans Django 4.0.

Voir Fonctionnalités rendues obsolètes dans Django 3.0 pour les détails de ces changements, ainsi que pour savoir comment supprimer l’utilisation de ces fonctionnalités.

- `django.utils.http.urlquote()`, `urlquote_plus()`, `urlunquote()` et `urlunquote_plus()` ont été supprimées.

- `django.utils.encoding.force_text()` et `smart_text()` ont été supprimées.

- `django.utils.translation.ugettext()`, `ugettext_lazy()`, `ugettext_noop()`, `ungettext()` et `ungettext_lazy()` ont été supprimées.

- `django.views.i18n.set_language()` ne définit plus la langue de l’utilisateur dans `request.session` (clé `_language`).

- `alias=None` est obligatoire dans la signature des sous-classes de `django.db.models.Expression.get_group_by_cols()`.

- `django.utils.text.unescape_entities()` a été supprimée.

- `django.utils.http.is_safe_url()` a été supprimée.

Voir Fonctionnalités rendues obsolètes dans Django 3.1 pour les détails de ces changements, ainsi que pour savoir comment supprimer l’utilisation de ces fonctionnalités.

- Le réglage `PASSWORD_RESET_TIMEOUT_DAYS` a été supprimé.

- L’expression de requête `isnull` n’accepte plus de valeurs non booléennes dans sa partie droite.

- La classe d’exception `django.db.models.query_utils.InvalidQuery` a été supprimée.

- Le point d’entrée `django-admin.py` a été supprimé.

- La méthode `HttpRequest.is_ajax()` a été supprimée.

- La prise en charge du format de codage des cookies d’avant Django 3.1 utilisé par `django.contrib.messages.storage.cookie.CookieStorage` a été supprimée.

- La prise en charge des jetons de réinitialisation des mots de passe d’avant Django 3.1 dans le site d’administration (qui utilise l’algorithme de hachage SHA-1) a été supprimée.

- La prise en charge du format de codage des sessions d’avant Django 3.1 a été supprimée.

- La prise en charge des signatures `django.core.signing.Signer` d’avant Django 3.1 (utilisant l’algorithme de hachage SHA-1) a été supprimée.

- La prise en charge des signatures `django.core.signing.dumps()` d’avant Django 3.1 (utilisant l’algorithme de hachage SHA-1) a été supprimée dans `django.core.signing.loads()`.

- La prise en charge des sessions d’utilisateurs d’avant Django 3.1 (utilisant l’algorithme de hachage SHA-1) a été supprimée.

- L’argument `get_response` de `django.utils.deprecation.MiddlewareMixin.__init__()` est obligatoire et n’accepte plus `None`.

- L’argument `providing_args` de `django.dispatch.Signal` a été supprimé.

- Le paramètre `length` de `django.utils.crypto.get_random_string()` est obligatoire.

- Le message `list` de `ModelMultipleChoiceField` a été supprimé.

- La prise en charge de la transmission d’alias de colonnes bruts à `QuerySet.order_by()` a été supprimée.

- Le champ de modèle `NullBooleanField` a été supprimé, sauf pour la prise en charge des migrations historiques.

- `django.conf.urls.url()` a été supprimée.

- Le champ de modèle `django.contrib.postgres.fields.JSONField` a été supprimé, sauf pour la prise en charge des migrations historiques.

- `django.contrib.postgres.fields.jsonb.KeyTransform` et `django.contrib.postgres.fields.jsonb.KeyTextTransform` ont été supprimées.

- `django.contrib.postgres.forms.JSONField` a été supprimé.

- Les balises de gabarit `{% ifequal %}` et `{% ifnotequal %}` ont été supprimées.

- Le réglage temporaire `DEFAULT_HASHING_ALGORITHM` a été supprimé.