# Documentation Django 5.2.8

# Notes de publication de Django 3.1

4 août 2020

Bienvenue dans Django 3.1 !

Ces notes de publications couvrent les nouvelles fonctionnalités, ainsi que certaines modifications non rétro-compatibles dont il faut être au courant lors de la mise à jour depuis Django 3.0 ou des versions plus anciennes. Nous avons abandonné certaines fonctionnalités qui ont atteint la fin de leur cycle d’obsolescence et 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 3.1 requiert Python 3.6, 3.7, 3.8 ou 3.9 (dès 3.1.3). Nous recommandons vivement et nous ne prenons officiellement en charge que la dernière publication de chaque série.

## Quoi de neuf dans Django 3.1

### Prise en charge des vues et intergiciels asynchrones

Django prend dorénavant en charge un chemin de requête pleinement asynchrone, y compris :

- des vues asynchrones

- des intergiciels asynchrones

- des tests et un client de test asynchrones

Pour débuter avec des vues asynchrones, vous devez déclarer une vue avec `async def`:

    async def my_view(request):
        await asyncio.sleep(0.5)
        return HttpResponse("Hello, async world!")

Toutes les fonctionnalités asynchrones sont prises en charge que vous fonctionniez en mode WSGI ou ASGI. Cependant, en utilisant du code asynchrone en mode WSGI, des limites de performance doivent être attendues. Vous pouvez en apprendre davantage sur ce sujet dans la documentation Gestion du code asynchrone.

Vous êtes libre de mélanger des vues, intergiciels et tests asynchrones et synchrones autant que vous voulez. Django va s’assurer que vous vous trouviez toujours dans le bon contexte d’exécution. Nous nous attendons à ce que la plupart des projets conservent la majorité de leurs vues synchrones et n’aient qu’une petite partie de leurs vues en mode asynchrone, mais c’est à vous d’en décider.

L’ORM, la couche de cache et d’autres parties du code de Django qui effectuent des appels réseau à longue durée ne gèrent pas encore l’accès asynchrone. Nous espérons ajouter cette prise ne charge dans les prochaines publications. Les vues asynchrones sont idéales quand vous effectuez beaucoup d’appels d’API ou de requêtes HTTP dans vos vues. Il est maintenant possible d’effectuer tous ces appels HTTP nativement en parallèle pour augmenter considérablement la vitesse d’exécution de vos vues.

La prise ne charge de code asynchrone devrait être entièrement rétrocompatible et nous avons tenté de nous assurer qu’il n’y a pas de régression de performance pour le code synchrone existant. Il ne devrait pas y avoir d’effet décelable pour un projet Django existant.

### Champ JSONField pour tous les moteurs de bases de données qui le permetttent

Django inclut dorénavant des champs `models.JSONField` et `forms.JSONField` qui peuvent être utilisés avec tous les moteurs de base de données qui offrent ce champ. Les deux champs permettent de personnaliser leurs codeur et décodeur JSON. Le champ de modèle gère l’introspection, les interrogations et transformations qui étaient précédemment disponibles uniquement pour PostgreSQL

    from django.db import models

    class ContactInfo(models.Model):
        data = models.JSONField()

    ContactInfo.objects.create(
        data={
            "name": "John",
            "cities": ["London", "Cambridge"],
            "pets": {"dogs": ["Rufus", "Meg"]},
        }
    )
    ContactInfo.objects.filter(
        data__name="John",
        data__pets__has_key="dogs",
        data__cities__contains="London",
    ).delete()

Si votre projet utilise `django.contrib.postgres.fields.JSONField` et les champs de formulaires et transformations relatives, vous devriez ajuster les importations pour utiliser les nouveaux champs, puis produire et appliquer une migration de base de données. Pour l’instant, les anciens champs et transformations sont conservés sous forme de références aux nouveaux emplacements et sont marqués comme obsolètes à partir de cette publication.

### Réglage `DEFAULT_HASHING_ALGORITHM`

The new `DEFAULT_HASHING_ALGORITHM` transitional setting allows specifying the default hashing algorithm to use for encoding cookies, password reset tokens in the admin site, user sessions, and signatures created by `django.core.signing.Signer` and `django.core.signing.dumps()`.

Support for SHA-256 was added in Django 3.1. If you are upgrading multiple instances of the same project to Django 3.1, you should set `DEFAULT_HASHING_ALGORITHM` to `'sha1'` during the transition, in order to allow compatibility with the older versions of Django. Note that this requires Django 3.1.1+. Once the transition to 3.1 is complete you can stop overriding `DEFAULT_HASHING_ALGORITHM`.

Ce réglage est obsolète dès cette publication, car la prise en charge des jetons, cookies, sessions et signatures utilisant l’algorithme SHA-1 sera supprimée dans Django 4.0.

### Fonctionnalités mineures

#### `django.contrib.admin`

- Le nouveau filtre `django.contrib.admin.EmptyFieldListFilter` pour `ModelAdmin.list_filter` permet de filtrer les valeurs vides (chaînes vides et valeurs nulles) dans la vue pour modification de l’administration.

- Les filtres dans la barre latérale de droite de la vue pour modification du site d’administration contient dorénavant un lien pour effacer tous les filtres.

- Le site d’administration possède maintenant une barre latérale sur les grands écrans pour une navigation simplifiée. Elle est activée par défaut mais peut être désactivée en utilisant un `AdminSite` personnalisé et en définissant son attribut `AdminSite.enable_nav_sidebar` à `False`.

  Le rendu de la barre latérale nécessite d’accéder à la requête en cours pour pouvoir définir les possibilités de rôles CSS et ARIA. Cela nécessite la présence de `'django.template.context_processors.request'` dans l’option `'context_processors'` de :setting:`OPTIONS <TEMPLATES-OPTIONS> `.

- Les formulaires en ligne `extra` initialement vides peuvent dorénavant être supprimés, de la même façon que pour ceux créés dynamiquement.

- `XRegExp` a été mis à jour de la version 2.0.0 à 3.2.0.

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

- La bibliothèque Select2 a été mise à jour de la version 4.0.7 vers 4.0.13.

#### `django.contrib.auth`

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

- Le nouveau réglage `PASSWORD_RESET_TIMEOUT` permet de définir le nombre de secondes pendant lequel un lien de réinitialisation de mot de passe est valide. Ce réglage est privilégié par rapport au réglage obsolète `PASSWORD_RESET_TIMEOUT_DAYS` qui sera supprimé dans Django 4.0.

- Le mécanisme de réinitialisation de mot de passe utilise dorénavant l’algorithme de hachage SHA-256. La prise en charge des jetons utilisant l’ancien algorithme de hachage restera jusqu’à Django 4.0.

- `AbstractBaseUser.get_session_auth_hash()` utilise dorénavant l’algorithme de hachage SHA-256. La prise en charge des sessions utilisateurs utilisant l’ancien algorithme de hachage restera jusqu’à Django 4.0.

#### `django.contrib.contenttypes`

- La nouvelle option `remove_stale_contenttypes --include-stale-apps` permet de supprimer les types de contenu périmés provenant des applications précédemment installées qui ont été supprimées de `INSTALLED_APPS`.

#### `django.contrib.gis`

- La requête `relate` est dorénavant prise en charge avec MariaDB.

- La propriété `LinearRing.is_counterclockwise` a été ajoutée.

- `AsGeoJSON` est dorénavant prise en charge avec Oracle.

- Les fonctions `AsWKB` et `AsWKT` ont été ajoutées.

- La prise en charge de PostGIS 3 et GDAL3 a été ajoutée.

#### `django.contrib.humanize`

- Le filtre de gabarit `intword` prend désormais en charge les nombres entiers négatifs.

#### `django.contrib.postgres`

- La nouvelle classe `BloomIndex` permet de créer des index `bloom` dans la base de données. La nouvelle opération de migration `BloomExtension` installe l’extension `bloom` pour ajouter la prise en charge de cet index.

- `get_FOO_display()` prend dorénavant en charge les champs `ArrayField` et `RangeField`.

- Les nouvelles expressions de requête `rangefield.lower_inc`, `rangefield.lower_inf`, `rangefield.upper_inc` et `rangefield.upper_inf` permettent d’interroger `RangeField` selon un type de limite.

- `rangefield.contained_by` prends dorénavant en charge les champs `SmallAutoField`, `AutoField`, `BigAutoField`, `SmallIntegerField` et `DecimalField`.

- `SearchQuery` prend dorénavant en charge le type de recherche `'websearch'` avec PostgreSQL 11+.

- `SearchQuery.value` prend dorénavant en charge les expressions de requête.

- La nouvelle classe `SearchHeadline` permet de mettre en évidence les résultats de recherche.

- La requête `search` prend dorénavant en charge les expressions de requête.

- Le nouveau paramètre `cover_density` de `SearchRank` permet de classer les résultats par taux de couverture.

- Le nouveau paramètre `normalization` de `SearchRank` permet de normaliser les classements.

- Le nouvel attribut `ExclusionConstraint.deferrable` permet de créer des contraintes d’exclusion différables.

#### `django.contrib.sessions`

- Le réglage `SESSION_COOKIE_SAMESITE` autorise dorénavant la valeur `'None'` (chaîne) pour indiquer explicitement que le cookie doit être envoyé avec toutes les requêtes (de même site ou inter-sites).

#### `django.contrib.staticfiles`

- Le réglage `STATICFILES_DIRS` accepte maintenant les chemins `pathlib.Path`.

#### Cache

- Le décorateur `cache_control()` et la méthode `patch_cache_control()` acceptent dorénavant plusieurs noms de champs dans la directive `no-cache` de l’en-tête `Cache-Control`, en accord avec la RFC 7234 Section 5.2.2.2.

- `delete()` now returns `True` if the key was successfully deleted, `False` otherwise.

#### CSRF

- Le réglage `CSRF_COOKIE_SAMESITE` autorise dorénavant la valeur `'None'` (chaîne) pour indiquer explicitement que le cookie doit être envoyé avec toutes les requêtes (de même site ou inter-sites).

#### Email

- Le réglage `EMAIL_FILE_PATH`, utilisé par le moteur de messagerie basé sur des fichiers accepte dorénavant les chemins `pathlib.Path`.

#### Signalement d’erreurs

- `django.views.debug.SafeExceptionReporterFilter` filtre dorénavant les valeurs sensibles dans `request.META` dans les rapports d’exceptions.

- Les nouveaux attributs `SafeExceptionReporterFilter.cleansed_substitute` et `SafeExceptionReporterFilter.hidden_settings` permettent de personnaliser les réglages sensibles et le filtrage de `request.META` dans les rapports d’exceptions.

- La vue de débogage technique 404 respecte dorénavant `DEFAULT_EXCEPTION_REPORTER_FILTER` lorsqu’elle applique le filtrage des réglages.

- Le nouveau réglage `DEFAULT_EXCEPTION_REPORTER` permet de fournir une sous-classe de `django.views.debug.ExceptionReporter` pour personnaliser la génération des rapports d’exceptions. Voir Rapports d’erreur personnalisés pour plus de détails.

#### Stockage de fichier

- La méthode `FileSystemStorage.save()` accepte maintenant les chemins `pathlib.Path`.

- `FileField` et `ImageField` acceptent dorénavant un objet exécutable comme valeur de `storage`. Cela permet de modifier le stockage utilisé au moment de l’exécution, choisissant par exemple différents stockages en fonction de l’environnement.

#### Formulaires

- `ModelChoiceIterator`, utilisé par `ModelChoiceField` et `ModelMultipleChoiceField`, utilise dorénavant `ModelChoiceIteratorValue` qui peut être utilisé par les composants pour accéder aux instances de modèles. Voir Itération sur les choix relationnels pour plus de détails.

- `django.forms.DateTimeField` accepte dorénavant les dates dans un sous-ensemble des formats de date/heure ISO 8601, y compris le fuseau horaire facultatif, par ex. `2019-10-10T06:47`, `2019-10-10T06:47:23+04:00` ou `2019-10-10T06:47:23Z`. Le fuseau horaire est toujours conservé s’il est présent, et des dates/heures conscientes de leur fuseau sont toujours renvoyées même si `USE_TZ` vaut `False`.

  De plus, `DateTimeField` utilise dorénavant `DATE_INPUT_FORMATS` en plus de `DATETIME_INPUT_FORMATS` lors de la conversion d’une valeur saisie dans un champ vers une valeur `datetime`.

- `MultiWidget.widgets` accepte dorénavant un dictionnaire qui permet de personnaliser les attributs `name` des sous-composants.

- La nouvelle propriété `BoundField.widget_type` peut être utilisée pour ajuster dynamiquement la production des formulaires en fonction du type de composant.

#### Internationalisation

- Le réglage `LANGUAGE_COOKIE_SAMESITE` autorise dorénavant la valeur `'None'` (chaîne) pour indiquer explicitement que le cookie doit être envoyé avec toutes les requêtes (de même site ou inter-sites).

- La prise en charge des traductions en arabe algérien, igbo, kirghize, tadjik et turkmène a été ajoutée.

#### Commandes d’administration

- La nouvelle option `check --database` permet d’indiquer des alias de base de données lors de l’exécution des contrôles systèmes `database`. Précédemment, ces contrôles étaient activés pour toutes les bases configurées dans `DATABASES` lorsqu’on passait le drapeau `database` à la commande.

- La nouvelle option `migrate --check` fait quitter la commande avec un statut différent de 0 lorsque des migrations non appliquées sont détectées.

- Le nouveau paramètre `returncode` de `CommandError` permet de personnaliser le statut de sortie des commandes d’administration.

- La nouvelle option `dbshell -- PARAMÈTRES` permet de passer des paramètres supplémentaires au client de ligne de commande de la base de données.

- Les commandes `flush` et `sqlflush` incluent dorénavant du code SQL pour réinitialiser les séquences avec SQLite.

#### Modèles

- La nouvelle fonction `ExtractIsoWeekDay` extrait les jours de semaine ISO-8601 des champs `DateField` et `DateTimeField`, et la nouvelle expression de requête `iso_week_day` permet d’interroger selon un jour de semaine ISO-8601.

- `QuerySet.explain()` prend dorénavant en charge :

  - le format `TREE` de MySQL 8.0.16+ ;

  - l’option `analyze` de MySQL 8.0.18+ et MariaDB.

- Le champ `PositiveBigIntegerField` a été ajouté ; il est similaire à `PositiveIntegerField` sauf qu’il ne permet des valeurs que jusqu’à une certaine limite (dépendante de la base de données). Les valeurs de `0` à `9223372036854775807` sont valables pour toutes les bases de données prises en charge par Django.

- La nouvelle option `RESTRICT` du paramètre `on_delete` de `ForeignKey` et de `OneToOneField` émule le comportement de la contrainte SQL `ON DELETE RESTRICT`.

- `CheckConstraint.check` now supports boolean expressions.

- Les méthodes `RelatedManager.add()`, `create()` et `set()` acceptent dorénavant les objets exécutables comme valeurs du paramètre `through_defaults`.

- Le nouveau paramètre `is_dst` de `QuerySet.datetimes()` détermine le traitement des heures non existantes ou ambiguës.

- La nouvelle méthode `bitxor()` de l’expression `F` permet l”opération bit-à-bit XOR.

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

- La méthode `DatabaseOperations.sql_flush()` génère dorénavant du code SQL plus efficace avec MySQL en utilisant des instructions `DELETE` au lieu de `TRUNCATE` pour les tables qui ne nécessitent pas la réinitialisation de leurs séquences.

- SQLite functions are now marked as `deterministic` on Python 3.8+. This allows using them in check constraints and partial indexes.

- Le nouvel attribut `UniqueConstraint.deferrable` permet de créer des contraintes d’unicité différables.

#### Pagination

- Il est maintenant possible d’itérer sur des objets `Paginator` pour produire ses pages.

#### Requêtes et réponses

- Si `ALLOWED_HOSTS` est vide et que `DEBUG=True`, les sous-domaines de localhost sont maintenant autorisés dans l’en-tête `Host`, par ex. `static.localhost`.

- `HttpResponse.set_cookie()` et `HttpResponse.set_signed_cookie()` autorisent désormais l’utilisation de `samesite='None'` (chaîne) pour indiquer explicitement que le cookie doit être envoyé avec toutes les requêtes du même site et inter-sites.

- La nouvelle méthode `HttpRequest.accepts()` renvoie un booléen indiquant si la requête accepte le type MIME donné en fonction de l’en-tête HTTP `Accept`.

#### Sécurité

- Le réglage `SECURE_REFERRER_POLICY` contient dorénavant par défaut la valeur `'same-origin'`. Avec cette valeur, `SecurityMiddleware` définit l’en-tête Politique de référencement à `same-origin` pour toutes les réponses qui ne l’ont pas déjà. Cela évite que l’en-tête `Referer` soit envoyé à d’autres origines. Si vous avez besoin du comportement précédent, définissez explicitement `SECURE_REFERRER_POLICY` à `None`.

- L’algorithme par défaut de `django.core.signing.Signer`, `django.core.signing.loads()` et `django.core.signing.dumps()` est dorénavant SHA-256. La prise en charge de signatures faites avec l’ancien algorithme SHA-1 sera conservée jusqu’à Django 4.0.

  De plus, le nouveau paramètre `algorithm` de `Signer` permet de personnaliser l’algorithme de hachage.

#### Gabarits

- Les balises de gabarit `translate` and `blocktranslate` pour la régionalisation dans le code des gabarits ont été renommées. Les anciens alias de ces balises (`trans` et `blocktrans`) continueront de fonctionner et seront conservés dans le futur proche.

- La balise de gabarit `include` accepte maintenant des objects itérables de noms de gabarits.

#### Tests

- `SimpleTestCase` implément dorénavant la méthode `debug()` pour permettre de lancer un test sans collecter son résultat et intercepter les exceptions. Ceci peut être utiliser pour pouvoir exécuter les tests avec un débogueur.

- Le nouveau réglage de base de données de test `MIGRATE` permet de désactiver les migrations pendant la création d’une base de données de test.

- `DiscoverRunner` can now discard output for passing tests using the `test --buffer` option.

- `DiscoverRunner` n’exécute plus les contrôles systèmes pour les bases de données qui ne sont pas référencées par les tests.

- La terminaison (teardown) de la classe `TransactionTestCase` est dorénavant plus rapide avec MySQL en raison des améliorations de la command `flush`. Comme effet de bord, cette classe de réinitialise plus automatiquement les séquences dans le processus de terminaison. Activez `TransactionTestCase.reset_sequences` si vos tests ont besoin de cette fonctionnalité.

#### URL

- Les convertisseurs de chemin peuvent dorénavant générer `ValueError` dans `to_url()` pour indiquer qu’aucune correspondance n’a été trouvée dans la résolution inverse des URL.

#### Utilitaires

- `filepath_to_uri()` accepte maintenant les chemins `pathlib.Path`.

- `parse_duration()` prend dorénavant en charge les séparateurs virgules pour les fractions décimales dans le format ISO 8601.

- `parse_datetime()`, `parse_duration()` et `parse_time()` acceptent dorénavant les séparateurs virgules pour les millisecondes.

#### Divers

- Le moteur SQLite accepte dorénavant les valeurs `pathlib.Path` dans son réglage `NAME`.

- Le fichier `settings.py` généré par la commande `startproject` utilise dorénavant un chemin `pathlib.Path` au lieu de `os.path` pour la construction des chemins du système de fichiers.

- Le réglage `TIME_ZONE` est désormais autorisé pour les bases de données qui gèrent les fuseaux horaires.

## Changements incompatibles avec les anciennes versions dans Django 3.1

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

- `DatabaseOperations.fetch_returned_insert_columns()` exige dorénavant un paramètre supplémentaire `returning_params`.

- La propriété `connection.timezone` vaut dorénavant `'UTC'` par défaut ou la valeur de `TIME_ZONE` lorsque `USE_TZ` vaut `True` avec les bases de données prenant en charge les fuseaux horaires. Précédement, il contenait `None` avec les bases de données prenant en charge les fuseaux horaires.

- La propriété `connection._nodb_connection` a été modifiée en une méthode `connection._nodb_cursor()` et renvoie dorénavant un gestionnaire de contexte produisant un curseur et fermant automatiquement ce curseur et sa connexion en sortant du contexte avec l’instruction `with`.

- `DatabaseClient.runshell()` exige dorénavant un paramètre supplémentaire `parameters` sous forme de liste de paramètres supplémentaires à transmettre au client de ligne de commande.

- Le paramètre positionnel `sequences` de `DatabaseOperations.sql_flush()` est remplacé par le paramètre `reset_sequences`, purement mot-clé et booléen. Si `True`, les séquences des tables tronquées seront réinitialisées.

- Le paramètre `allow_cascade` de `DatabaseOperations.sql_flush()` est dorénavant un paramètre uniquement par mot-clé.

- Le paramètre positionnel `using` de `DatabaseOperations.execute_sql_flush()` a été supprimé. La méthode utilise dorénavant la base de données de l’instance appelée.

- Les moteurs de base de données externes doivent implémenter la prise en charge de `JSONField` ou définir `DatabaseFeatures.supports_json_field` à `False`. Si le stockage de primitives n’est pas pris en charge, il faut définir `DatabaseFeatures.supports_primitives_in_json_field` à `False`. Si un type de données JSON spécifique existe, définissez `DatabaseFeatures.has_native_json_field` à `True`. Si `jsonfield.contains` et `jsonfield.contained_by` ne sont pas pris en charge, définissez `DatabaseFeatures.supports_json_field_contains` à `False`.

- Les moteurs de base de données de tierce-partie doivent implémenter l’introspection pour `JSONField` ou définir `can_introspect_json_field` à `False`.

### Abandon de la prise en charge de MariaDB 10.1

La prise en charge amont de MariaDB 10.1 se termine en octobre 2020. Django 3.1 prend en charge MariaDB 10.2 et plus récent.

### Navigateurs pris en charge par `contrib.admin`

Le site d’administration ne prend plus en charge le navigateur obsolète Internet Explorer. Consultez la FAQ de l’administration pour plus de détails sur les navigateurs pris en charge.

### L’attribut `max_length` de `AbstractUser.first_name` a été étendu à 150

Une migration pour `django.contrib.auth.models.User.first_name` a été incluse. Si vous disposez d’un modèle utilisateur personnalisé héritant de `AbstractUser`, vous devrez produire et appliquer une migration de base de données pour votre modèle.

Si vous souhaitez conserver la limite de 30 caractères pour les prénoms, utilisez un formulaire personnalisé

    from django import forms
    from django.contrib.auth.forms import UserChangeForm

    class MyUserChangeForm(UserChangeForm):
        first_name = forms.CharField(max_length=30, required=False)

Si vous souhaitez conserver cette restriction dans le site d’administration lors de l’édition des utilisateurs, définissez `UserAdmin.form` à ce formulaire

    from django.contrib.auth.admin import UserAdmin
    from django.contrib.auth.models import User

    class MyUserAdmin(UserAdmin):
        form = MyUserChangeForm

    admin.site.unregister(User)
    admin.site.register(User, MyUserAdmin)

### Divers

- Les clés de cache utilisées par `cache` et générées par `make_template_fragment_key()` sont différentes des clés générées par les anciennes versions de Django. Après la mise à jour vers Django 3.1, la première requête vers tout fragment de gabarit mis en cache va devoir remplir à nouveau le cache.

- La logique derrière la décision de renvoyer une redirection ou une réponse HTTP 204 dans la vue `set_language()` est dorénavant basée sur l’en-tête HTTP `Accept` au lieu de la présence de l’en-tête HTTP `X-Requested-With`.

- Les importations de compatibilité pour `django.core.exceptions.EmptyResultSet` dans `django.db.models.query`, `django.db.models.sql` et `django.db.models.sql.datastructures` ont été supprimées.

- L’importation de compatibilité pour `django.core.exceptions.FieldDoesNotExist` dans `django.db.models.fields` a été supprimée.

- Les importations de compatibilité pour `django.forms.utils.pretty_name()` et `django.forms.boundfield.BoundField` dans `django.forms.forms` ont été supprimées.

- Les importations de compatibilité pour `Context`, `ContextPopException` et `RequestContext` dans `django.template.base` ont été supprimées.

- L’importation de compatibilité pour `django.contrib.admin.helpers.ACTION_CHECKBOX_NAME` dans `django.contrib.admin` a été supprimée.

- Les réglages `STATIC_URL` et `MEDIA_URL` définis à des chemins relatifs sont dorénavant préfixés par la valeur `SCRIPT_NAME` fournie par le serveur (ou `/` si non défini). Ce changement ne devrait pas affecter les réglages définis à des URL valides ou des chemins absolus.

- `ConditionalGetMiddleware` n’ajoute plus l’en-tête `ETag` aux réponses qui ont un contenu `content` vide.

- `django.utils.decorators.classproperty()` decorator is made public and moved to `django.utils.functional.classproperty`.

- Le filtre de gabarit `floatformat` produit dorénavant `0` (positif) pour les nombres négatifs arrondis à zéro.

- Les options `Meta.ordering` et `Meta.unique_together` des modèles dans les modules `django.contrib` qui étaient précédemment des tuples sont maintenant des listes.

- Le composant calendrier du site d’administration gère dorénavant les années sur deux chiffres selon la spécification Open Group, c’est-à-dire que les valeurs entre 69 et 99 sont attribuées au siècle précédent et les valeurs entre 0 et 68 sont attribuées au siècle actuel.

- Les formats de date uniquement ont été supprimés de la liste par défaut de `DATETIME_INPUT_FORMATS`.

- Le composant `FileInput` ne produit plus d’attribut HTML `required` lorsque des données initiales sont présentes.

- La classe non documentée `django.views.debug.ExceptionReporterFilter` a été supprimée. Comme le spécifie la documentation Rapports d’erreur personnalisés, les classes à placer dans `DEFAULT_EXCEPTION_REPORTER_FILTER` doivent hériter de `django.views.debug.SafeExceptionReporterFilter`.

- L’expiration du cache définie par le décorateur `cache_page()` a désormais la priorité sur la directive `max-age` de l’en-tête `Cache-Control`.

- Lorsqu’on passe un champ distant non local dans le paramètre `ForeignKey.to_field`, cela génère maintenant une exception `FieldError`.

- Le réglage `SECURE_REFERRER_POLICY` contient désormais `'same-origin'` par défaut. Consultez la section sécurité des nouveautés de Django 3.1 pour plus de détails.

- La commande d’administration `check` exécute dorénavant les contrôles systèmes `database` uniquement pour les alias de base de données indiqués par l’option `check --database`.

- La commande d’administration `migrate` exécute dorénavant les contrôles systèmes `database` uniquement pour la base de données de la migration.

- Les classes CSS du site d’administration `row1` et `row2` ont été supprimées en faveur des pseudo-classes `:nth-child(odd)` et `:nth-child(even)`.

- La fonction `make_password()` exige dorénavant que son paramètre soit une chaîne ou des octets. D’autres types de données doivent préalablement être forcés à l’un de ces types.

- Le paramètre non documenté `version` de la fonction `AsKML` a été supprimé.

- Les sérialiseurs JSON et YAML utilisés par `dumpdata` produisent toutes leurs données en Unicode par défaut. SI vous voulez conserver le comportement précédent, passez `ensure_ascii=True` au sérialiseur JSON ou `allow_unicode=False` au sérialiseur YAML.

- Le relanceur automatique ne surveille plus les changements dans les fichiers de traductions intégrés de Django.

- La version minimum de `mysqlclient` prise en charge est passée de 1.3.13 à 1.4.0.

- Les éléments non documentés `django.contrib.postgres.forms.InvalidJSONInput` et `django.contrib.postgres.forms.JSONString` ont été déplacés vers `django.forms.fields`.

- La classe `django.contrib.postgres.fields.jsonb.JsonAdapter` non documentée a été supprimée.

- La balise `{% localize off %}` et le filtre `unlocalize` ne tiennent plus compte du réglage `DECIMAL_SEPARATOR`.

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

- La classe Media produit dorénavant les balises `<script>` sans l’attribut `type` pour respecter les recommandations WHATWG.

- `ModelChoiceIterator`, utilisée par `ModelChoiceField` et `ModelMultipleChoiceField` produisent dorénavant des choix à 2 tuples contenant des instances de `ModelChoiceIteratorValue` comme premier élément `value` dans chaque choix. Dans la plupart des cas, le changement se fait de manière transparente, mais si vous avez besoin de la valeur du champ lui-même, utilisez plutôt l’attribut `ModelChoiceIteratorValue.value`.

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

### Le champ `JSONField` spécifique à PostgreSQL

`django.contrib.postgres.fields.JSONField` et `django.contrib.postgres.forms.JSONField` sont obsolètes et remplacées par `models.JSONField` et `forms.JSONField`.

Les transformations non documentées `django.contrib.postgres.fields.jsonb.KeyTransform` et `django.contrib.postgres.fields.jsonb.KeyTextTransform` sont aussi obsolètes et remplacées par les transformations dans `django.db.models.fields.json`.

Les nouveaux éléments `JSONField`, `KeyTransform` et `KeyTextTransform` peuvent être utilisés avec tous les moteurs de base de données pris en charge officiellement par Django.

### Divers

- Le réglage `PASSWORD_RESET_TIMEOUT_DAYS` a été rendu obsolète au profit de `PASSWORD_RESET_TIMEOUT`.

- L’utilisation non documentée de l’expression de requête `isnull` avec des valeurs non booléennes dans la partie droite est obsolète, utilisez plutôt `True` ou `False`.

- La classe d’exception tout juste documentée `django.db.models.query_utils.InvalidQuery` a été rendue obsolète au profit de `FieldDoesNotExist` et de `FieldError`.

- Le point d’entrée `django-admin.py` est obsolète ; il faut plutôt utiliser `django-admin`.

- La méthode `HttpRequest.is_ajax()` est osbolète car elle dépend d’une manière de signifier des appels AJAX propre à jQuery, alors que l’usage actuel tend à utiliser l”API fetch de JavaScript. En fonction de votre cas d’utilisation, vous pouvez soit écrire votre propre méthode de détection AJAX, soit utiliser la nouvelle méthode `HttpRequest.accepts()` si votre code se base sur l’en-tête HTTP `Accept` du client.

  Si vous écrivez votre propre méthode de détection AJAX, `request.is_ajax()` peut être reproduite exactement avec la condition `request.headers.get('x-requested-with') == 'XMLHttpRequest'`.

- La transmission de `None` comme premier paramètre de `django.utils.deprecation.MiddlewareMixin.__init__()` est obsolète.

- Le format de codage des valeurs de cookies utilisé par `CookieStorage` est différent du format généré par les anciennes versions de Django. La prise en charge de l’ancien format demeure jusqu’à Django 4.0.

- Le format de codage des sessions est différent du format généré par les anciennes versions de Django. La prise en charge de l’ancien format demeure jusqu’à Django 4.0.

- Le paramètre à titre purement documentaire `providing_args` de `Signal` est obsolète. Si vous comptez sur ce paramètre comme information de documentation, vous pouvez déplacer son contenu dans un commentaire de code.

- L’appel à `django.utils.crypto.get_random_string()` sans paramètre de longueur `length` est obsolète.

- Le message `list` de `ModelMultipleChoiceField` a été rendu obsolète au profit de `invalid_list`.

- La transmission d’alias de colonnes bruts à `QuerySet.order_by()` est osbolète. Le même résultat peut être obtenu en passant préalablement les alias dans un objet `RawSQL`.

- The `NullBooleanField` model field is deprecated in favor of `BooleanField(null=True, blank=True)`.

- L’alias `django.conf.urls.url()` de `django.urls.re_path()` est obsolète.

- Les balises de gabarit `{% ifequal %}` et `{% ifnotequal %}` sont obsolètes et `{% if %}` doit être utilisé à la place. `{% if %}` couvre tous les cas d’utilisation, mais si vous voulez vraiment continuer à utiliser ces balises, elles peuvent être extraites du code de Django vers un de vos modules puis incluses comme balise intégrée dans l’option `'builtins'` de `OPTIONS`.

- Le réglage temporaire `DEFAULT_HASHING_ALGORITHM` est obsolète.

## Fonctionnalités supprimées dans 3.1

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

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

- `django.utils.timezone.FixedOffset` a été supprimée.

- `django.core.paginator.QuerySetPaginator` a été supprimée.

- L’attribut `Meta.ordering` des modèles n’affecte plus les requêtes `GROUP BY`.

- `django.contrib.postgres.fields.FloatRangeField` et `django.contrib.postgres.forms.FloatRangeField` ont été supprimés.

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

- `django.contrib.staticfiles.storage.CachedStaticFilesStorage` a été supprimée.

- La méthode `RemoteUserBackend.configure_user()` exige `request` comme premier paramètre positionnel.

- La prise en charge de `SimpleTestCase.allow_database_queries` et de `TransactionTestCase.multi_db` a été supprimée.