# Documentation Django 3.1.9.dev

# Notes de publication de Django 1.11

4 avril 2017

Bienvenue dans Django 1.11 !

Ces notes de publications couvrent les nouvelles fonctionnalités, ainsi que certaines modifications non rétro-compatibles dont il faut être au courant lors la mise à jour depuis Django 1.10 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.

Django 1.11 is designated as a long-term support release. It will receive security updates for at least three years after its release. Support for the previous LTS, Django 1.8, will end in April 2018.

## Compatibilité Python

Django 1.11 requires Python 2.7, 3.4, 3.5, 3.6, or 3.7 (as of 1.11.17). We highly recommend and only officially support the latest release of each series.

The Django 1.11.x series is the last to support Python 2. The next major release, Django 2.0, will only support Python 3.4+.

## Les avertissements d’obsolescence ne sont plus visibles par défaut

Au contraire des versions précédentes de Django, les avertissements d’obsolescence émis par Django ne sont plus affichés par défaut. C’est cohérent avec le comportement par défaut de Python.

Ce changement permet aux applications tierces de prendre en charge à la fois les versions Django 1.11 LTS et Django 1.8 LTS sans devoir ajouter du code pour éviter les avertissements d’obsolescence.

Après la publication de Django 2.0, nous suggérons aux applications tierces de ne plus prendre en charge les versions de Django plus anciennes que 1.11. À ce moment, vous devriez pouvoir exécuter les tests de votre projet en utilisant python -Wd afin de faire apparaître les avertissements d’obsolescence. Après avoir corrigé ceux-ci, votre application devrait être compatible avec Django 2.0.

## Quoi de neuf dans Django 1.11

### Index de modèles basés sur les classes

Le nouveau module `django.db.models.indexes` contient des classes qui facilitent la création d’index de base de données. Ces index peuvent être ajoutés aux modèles en utilisant l’option `Meta.indexes`.

La classe `Index` crée un index b-tree comme si vous indiquiez le paramètre `db_index` sur le champ de modèle ou `index_together` dans la classe `Meta` du modèle. Elle peut être héritée pour prendre en charge différents types d’index, tels que `GinIndex`. Elle permet aussi de définir le tri (ASC/DESC) pour les colonnes de l’index.

### Rendu des composants HTML basé sur des gabarits

Pour faciliter la personnalisation des composants de formulaire HTML, leur rendu est dorénavant effectué au travers du système de gabarits plutôt que dans le code Python. Voir L’API du rendu des formulaires.

Il est possible que vous ayez à adapter des composants personnalisés que vous avez écrits en raison de quelques changements non rétrocompatibles.

### Expressions `Subquery`

Les nouvelles expressions de base de données `Subquery` et `Exists` permettent la création de sous-requêtes explicites. Les sous-requêtes peuvent se référer à des champs de la requête parente avec la classe `OuterRef`.

### Fonctionnalités mineures

#### `django.contrib.admin`

- `ModelAdmin.date_hierarchy` peut dorénavant référencer des champs par-delà des relations.
- Le nouveau point d’entrée `ModelAdmin.get_exclude()` permet d’indiquer des champs à exclure en fonction de la requête ou de l’instance de modèle.
- Le gabarit `popup_response.html` peut dorénavant être surchargé par application, par modèle ou en définissant l’attribut `ModelAdmin.popup_response_template`.

#### `django.contrib.auth`

- Le nombre d’itération par défaut du hacheur de mot de passe PBKDF2 a été augmenté de 20%.
- Les vues classes `LoginView` et `LogoutView` remplacent les vues fonctions obsolètes `login()` et `logout()`.
- Les vues classes `PasswordChangeView`, `PasswordChangeDoneView`, `PasswordResetView`, `PasswordResetDoneView`, `PasswordResetConfirmView` et `PasswordResetCompleteView` remplacent les vues fonctions obsolètes `password_change()`, `password_change_done()`, `password_reset()`, `password_reset_done()`, `password_reset_confirm()` et `password_reset_complete()`.
- Le nouvel attribut `post_reset_login` de `PasswordResetConfirmView` permet de connecter automatiquement un utilisateur à la suite d’une réinitialisation de mot de passe fructueuse. Si plusieurs moteurs `AUTHENTICATION_BACKENDS` sont configurés, indiquez lequel sera utilisé en définissant l’attribut `post_reset_login_backend`.
- Pour éviter l’éventualité d’une divulgation du jeton de réinitialisation du mot de passe par l’en-tête HTTP Referer (par exemple si la page de réinitialisation inclut des références à des fichiers CSS ou JavaScript hébergés sur d’autres domaines), la vue `PasswordResetConfirmView` (mais pas la vue fonction obsolète `password_reset_confirm()`) stocke le jeton dans une session et redirige sur elle-même pour présenter le formulaire de changement de mot de passe à l’utilisateur sans devoir inclure le jeton dans l’URL.
- `update_session_auth_hash()` effectue dorénavant une rotation de clé de session pour permettre à un changement de mot de passe d’invalider des cookies de session volés.
- Le nouvel attribut `success_url_allowed_hosts` de `LoginView` et `LogoutView` permet d’indiquer un ensemble d’hôtes qui sont fiables pour la redirection après connexion ou déconnexion.
- Du contenu d’aide `help_text` a été ajouté pour les validateurs de mot de passe de `UserCreationForm`.
- La requête `HttpRequest` est dorénavant transmise à `authenticate()` qui à son tour la transmet au moteur d’authentification si celui-ci accepte un paramètre `request`.
- Le signal `user_login_failed()` reçoit dorénavant un paramètre `request`.
- `PasswordResetForm` prend en charge des modèles d’utilisateur personnalisés qui utilisent un champ d’adresse de courriel nommé autrement que `'email'`. Définissez `CustomUser.EMAIL_FIELD` à la valeur du nom de champ concerné.
- `get_user_model()` peut maintenant être appelé au moment de l’importation, même dans les modules qui définissent des modèles.

#### `django.contrib.contenttypes`

- Lorsque des types de contenu périmés sont détectés dans la commande `remove_stale_contenttypes`, vous verrez maintenant apparaître une liste des objets liés qui seront aussi supprimés, tels que `auth.Permission`. Précédemment, seuls les types de contenu étaient énumérés (et cette invite apparaissait après `migrate` plutôt que dans une commande séparée).

#### `django.contrib.gis`

- Les nouvelles méthodes `GEOSGeometry.from_gml()` et `OGRGeometry.from_gml()` permettent de créer des objets géométriques à partir du format GML.
- La prise en charge de l’expression de recherche `dwithin` a été ajoutée pour SpatiaLite.
- Les fonctions `Area` et `Distance` ainsi que les requêtes de distance fonctionnent dorénavant aussi sur SpatiaLite avec des coordonnées géodésiques.
- The OpenLayers-based form widgets now use `OpenLayers.js` from `https://cdnjs.cloudflare.com` which is more suitable for production use than the old `https://openlayers.org/` source. They are also updated to use OpenLayers 3.
- Les migrations PostGIS peuvent dorénavant modifier les dimensions de champs.
- Added the ability to pass the `size`, `shape`, and `offset` parameters when creating `GDALRaster` objects.
- La prise en charge SpatiaLite des fonctions `IsValid` et `MakeValid` ainsi que de l’expression de recherche `isvalid` a été ajoutée.
- La prise en charge Oracle des fonctions `AsGML`, `BoundingCircle` et `IsValid` ainsi que de l’expression de recherche `isvalid` a été ajoutée.

#### `django.contrib.postgres`

- Le nouveau paramètre `distinct` de `StringAgg` détermine si les valeurs concaténées seront distinctes.
- Les nouvelles classes `GinIndex` et `BrinIndex` permettent de créer des index de type `GIN` et `BRIN` dans la base de données.
- `JSONField` accepte un nouveau paramètre `encoder` pour définir une classe personnalisée se chargeant du codage des types de données non pris en charge par le codeur standard.
- La classe mixin `CIText` et l’opération de migration `CITextExtension` sont nouvelles et permettent d’exploiter l’extension `citext` de PostgreSQL dans l’optique de requêtes insensibles à la casse. Trois champs sont fournis : `CICharField`, `CIEmailField` et `CITextField`.
- La nouvelle fonction `JSONBAgg` permer d’agréger des valeurs sous forme de tableau JSON.
- Le champ de modèle `HStoreField` et le champ de formulaire `HStoreField` permettent de stocker des valeurs nulles.

#### Cache

- Les moteurs Memcached transmettent dorénavant les contenus de `OPTIONS` comme paramètres nommés aux constructeurs clients, permettant un contrôle plus fin du comportement du client. Voir la documentation des paramètres de cache pour des exemples.
- Les moteurs memcached autorisent dorénavant la définition de plusieurs serveurs sous forme de chaîne séparée par des virgules dans `LOCATION`, par commodité avec des service tiers qui utilisent de telles chaînes dans des variables d’environnement.

#### CSRF

- Le réglage `CSRF_USE_SESSIONS` a été ajouté pour permettre de stocker le jeton CSRF dans la session des utilisateurs plutôt que dans un cookie.

#### Moteurs de base de données

- Le paramètre `skip_locked` a été ajouté à `QuerySet.select_for_update()` avec PostgreSQL 9.5+ et Oracle pour exécuter des requêtes avec `FOR UPDATE SKIP LOCKED`.
- Le réglage `TEST['TEMPLATE']` a été ajouté pour permettre aux utilisateurs PostgreSQL d’indiquer un modèle à partir duquel la base de données de test est créée.
- `QuerySet.iterator()` utilise dorénavant des curseurs côté serveur avec PostgreSQL. Cette fonctionnalité transfère une partie de la charge mémoire (utilisée pour contenir les résultats de requête) vers la base de données et peut augmenter l’utilisation mémoire de la base de données.
- L’option `'isolation_level'` est maintenant prise en charge pour MySQL dans `OPTIONS` afin de pourvoir définir le niveau d’isolation des transactions. Pour éviter de possibles pertes de données, il est recommandé de dévier du niveau par défaut de MySQL, « repeatable read » et de passer à « read committed ».
- La prise en charge de `cx_Oracle` 5.3 a été ajoutée.

#### Email

- Le réglage `EMAIL_USE_LOCALTIME` a été ajouté pour permettre d’envoyer les en-têtes SMTP de date dans le fuseau horaire local plutôt qu’en temps UTC.
- `EmailMessage.attach()` and `attach_file()` now fall back to MIME type application/octet-stream when binary content that can’t be decoded as UTF-8 is specified for a text/* attachment.

#### Stockage de fichier

- Pour le rendre encapsulable dans `io.TextIOWrapper`, `File` possède dorénavant les méthodes `readable()`, `writable()` et `seekable()`.

#### Formulaires

- The new `empty_value` attribute on `CharField`, `EmailField`, `RegexField`, `SlugField`, and `URLField` allows specifying the Python value to use to represent « empty ».
- La nouvelle méthode `Form.get_initial_for_field()` renvoie la donnée initiale d’un champ de formulaire.

#### Internationalisation

- La mise en forme des nombres et le réglage `NUMBER_GROUPING` prennent en charge le groupement des chiffres non uniformes.

#### Commandes d’administration

- La nouvelle option `loaddata --exclude` permet d’exclure des modèles et des applications lors du chargement de données par des instantanés.
- La nouvelle option `diffsettings --default` permet de définir un module de réglage autre que celui de Django par défaut pour la comparaison.
- Les paramètres `app_label` limitent dorénavant la sortie de `showmigrations --plan`.

#### Migrations

- La prise en charge de la sérialisation d’objets `uuid.UUID` a été ajoutée.

#### Modèles

- La prise en charge de valeurs exécutables a été ajoutée dans le paramètre `defaults` de `QuerySet.update_or_create()` et `get_or_create()`.
- `ImageField` now has a default `validate_image_file_extension` validator. (This validator moved to the form field in Django 1.11.2.)
- Added support for time truncation to `Trunc` functions.
- Added the `ExtractWeek` function to extract the week from `DateField` and `DateTimeField` and exposed it through the `week` lookup.
- Added the `TruncTime` function to truncate `DateTimeField` to its time component and exposed it through the `time` lookup.
- Les expressions sont maintenant possibles dans `QuerySet.values()` et `values_list()`.
- La prise en charge d’expressions de requête dans les recherches qui acceptent plusieurs paramètres, telle que `range`, a été ajoutée.
- Il est dorénavant possible d’utiliser l’option `unique=True` avec `FileField`.
- Les paramètres `nulls_first` et `nulls_last` ont été ajoutés à `Expression.asc()` et `desc()` pour contrôler le tri des valeurs nulles.
- Les nouvelles méthodes `bitleftshift()` and `bitrightshift()` de l’expression `F` permettent des opérations de décalage de bit.
- Les méthodes `QuerySet.union()`, `intersection()` et `difference()` ont été ajoutées.

#### Requêtes et réponses

- `QueryDict.fromkeys()` a été ajoutée.
- `CommonMiddleware` définit dorénavant l’en-tête `Content-Length` pour les réponses qui ne sont pas de type flux.
- Le réglage `SECURE_HSTS_PRELOAD` a été ajouté pour permettre d’ajouter la directive `preload` à l’en-tête `Strict-Transport-Security`.
- `ConditionalGetMiddleware` ajoute dorénavant l’en-tête `ETag` aux réponses.

#### Sérialisation

- Le nouvel attribut `django.core.serializers.base.Serializer.stream_class` permet aux sous-classes de personnaliser le flux par défaut.
- Le codeur utilisé par le sérialiseur JSON peut dorénavant être personnalisé en passant un paramètre nommé `cls` à la fonction `serializers.serialize()`.
- `DjangoJSONEncoder` peut dorénavant sérialiser les objets `timedelta` (utilisé par `DurationField`).

#### Gabarits

- `mark_safe()` peut dorénavant être utilisé comme décorateur.
- Le moteur de gabarit `Jinja2` accepte dorénavant des processeurs de contexte en définissant l’option `'context_processors'` dans `OPTIONS`.
- La balise `regroup` renvoie dorénavant des `namedtuple` au lieu de dictionnaires, ce qui permet de développer directement l’objet groupe dans une boucle, par ex. `{% for grouper, list in regrouped %}`.
- Une balise de gabarit `resetcycle` a été ajoutée pour permettre de réinitialiser la séquence de la balise de gabarit `cycle`.
- Il est maintenant possible de définir des répertoires spécifiques à un `filesystem.Loader` particulier.

#### Tests

- `DiscoverRunner.get_test_runner_kwargs()` a été ajoutée pour permettre de personnaliser les paramètres nommés passés au lanceur de tests.
- L’option `test --debug-mode` a été ajoutée pour aider à dépanner les échecs de tests en définissant le réglage `DEBUG` à `True`.
- Les nouvelles fonctions `django.test.utils.setup_databases()` (déplacée de `django.test.runner`) et `teardown_databases()` facilitent la construction de ses propres lanceurs de tests.
- La prise en charge des sous-tests `unittest.TestCase.subTest()` a été ajoutée lorsque l’option `test --parallel` est utilisée.
- `DiscoverRunner` lance maintenant les contrôles système au début du lancement de tests. Surchargez la méthode `DiscoverRunner.run_checks()` si vous souhaitez désactiver ce comportement.

#### Validateurs

- Les nouveaux validateurs `FileExtensionValidator` et `validate_image_file_extension` permettent respectivement de valider des extensions de fichier et des fichiers images.

## Changements incompatibles avec les anciennes versions dans Django 1.11

### `django.contrib.gis`

- Pour simplifier la base de code et parce qu’il est maintenant plus facile de l’installer qu’au moment où `contrib.gis` a été introduit, GDAL est dorénavant une dépendance obligatoire de GeoDjango. Dans les versions précédentes, elle n’était requise qu’avec SQLite.
- `contrib.gis.maps` is removed as it interfaces with a retired version of the Google Maps API and seems to be unmaintained. If you’re using it, let us know.
- L’opérateur d’égalité `GEOSGeometry` compare dorénavant aussi avec le SRID.
- Les composants de formulaires basés sur OpenLayers utilisent dorénavant OpenLayers 3. Les gabarits `gis/openlayers.html` et `gis/openlayers-osm.html` ont été mis à jour. Vérifiez votre code si vous héritez de ces composants ou que vous étendez leur gabarit. De plus, les nouveaux composants fonctionnent un peu différemment des anciens. Au lieu de présenter une barre d’outils dans l’affichage, il faut cliquer pour commencer de dessiner, cliquer-glisser pour déplacer la carte et cliquer-glisser un point/arête/angle pour le déplacer.
- La prise en charge de SpatiaLite < 4.0 a été abandonnée.
- La prise en charge de GDAL 1.7 et 1.8 a été abandonnée.
- Les composants de formulaires dans `contrib.gis.forms.widgets` et `OpenLayersWidget` de l’administration utilisent l”API de rendu de formulaires à la place de `loader.render_to_string()`. Si vous utilisez un gabarit de composant personnalisé, vous devez être certain que le moteur de rendu de formulaires puisse le localiser. Par exemple, il est possible d’utiliser le moteur `TemplatesSetting`.

### `django.contrib.staticfiles`

- `collectstatic` peut maintenant échouer durant le post-traitement avec un stockage de fichiers statiques hachés si une référence croisée existe (par ex. `'foo.css'` référence `'bar.css'` qui lui-même référence `'foo.css'`) ou si la chaîne de fichiers référençant d’autres fichiers est trop profonde pour être résolue en quelques passes. Dans ce dernier cas, augmentez le nombre de passes en définissant `ManifestStaticFilesStorage.max_post_process_passes`.
- En utilisant `ManifestStaticFilesStorage`, les fichiers statiques non trouvés dans le manifeste au moment de l’exécution produisent dorénavant une exception `ValueError` au lieu de renvoyer un chemin inchangé. Vous pouvez revenir à l’ancien comportement en définissant `ManifestStaticFilesStorage.manifest_strict` à `False`.

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

- La méthode `DatabaseOperations.time_trunc_sql()` a été ajoutée pour gérer la troncature de `TimeField`. Elle accepte des paramètres `lookup_type` et `field_name` et renvoie le code SQL approprié pour tronquer le champ heure `field_name` à un objet heure restreint à la particule demandée. Le paramètre `lookup_type` peut valoir `'hour'`, `'minute'` ou `'second'`.
- La méthode `DatabaseOperations.datetime_cast_time_sql()` a été ajoutée pour gérer l’expression de recherche `time`. Elle accepte des paramètres `field_name` et `tzname` et renvoie le code SQL approprié pour forcer une valeur date/heure en une valeur heure.
- Pour activer la prise en charge de `FOR UPDATE SKIP LOCKED`, définissez `DatabaseFeatures.has_select_for_update_skip_locked = True`.
- The new `DatabaseFeatures.supports_index_column_ordering` attribute specifies if a database allows defining ordering for columns in indexes. The default value is `True` and the `DatabaseIntrospection.get_constraints()` method should include an `'orders'` key in each of the returned dictionaries with a list of `'ASC'` and/or `'DESC'` values corresponding to the ordering of each column in the index.
- `inspectdb` n’appelle plus `DatabaseIntrospection.get_indexes()` qui est obsolète. Les moteurs de base de données personnalisés doivent s’assurer que tous les types d’index sont renvoyés par `DatabaseIntrospection.get_constraints()`.
- La fonctionnalité `ignores_quoted_identifier_case` a été renommée en `ignores_table_name_case` pour refléter de manière plus précise son usage.
- Le paramètre nommé `name` a été ajouté à la méthode `DatabaseWrapper.create_cursor(self, name=None)` pour permettre l’emploi de curseurs côté serveur pour les moteurs qui les implémentent.

### Abandon de la prise en charge de PostgreSQL 9.2 et PostGIS 2.0

La prise en charge de PostgreSQL 9.2 par le projet amont se termine en septembre 2017. Par conséquent, Django 1.11 a défini la version 9.3 comme la version minimum de PostgreSQL officiellement prise en charge.

La prise en charge de PostGIS 2.0 a également été abandonnée car PostgreSQL 9.2 est la dernière version la prenant en charge.

De plus, la version minimum de psycopg2 prise en charge est passée de 2.4.5 à 2.5.4.

### `LiveServerTestCase` se lie au port zéro

Plutôt que de considérer un intervalle de ports et de les passer en boucle jusqu’à ce qu’un soit libre, `LiveServerTestCase` se lie au port zéro et se fie au système d’exploitation pour attribuer un port libre. La variable d’environnement `DJANGO_LIVE_TEST_SERVER_ADDRESS` n’est plus utilisée et par conséquent, l’option `manage.py test --liveserver` a été supprimée.

If you need to bind `LiveServerTestCase` to a specific port, use the `port` attribute added in Django 1.11.2.

### Protection contre les redirections non sûres dans les vues `django.contrib.auth` et `i18n`

`LoginView`, `LogoutView` (ainsi que leurs équivalents obsolètes basés sur des fonctions) et `set_language()` protègent les utilisateurs de redirections vers des URL « suivantes » non HTTPS lorsque l’application tourne sous HTTPS.

### `QuerySet.get_or_create()` et `update_or_create()` valident leurs paramètres

Pour éviter que des coquilles soient silencieusement ignorées, `get_or_create()` et `update_or_create()` vérifient que leurs paramètres soient des champs de modèle. Cela devrait être rétrocompatible pour autant que cela ne révèle pas une anomalie dans votre projet.

### `pytz` est une dépendance obligatoire et la prise en charge de `settings.TIME_ZONE = None` est supprimée

Pour simplifier la gestion des fuseaux horaires par Django, `pytz` est dorénavant une dépendance obligatoire. Cette bibliothèque est automatiquement installée en même temps que Django.

Support for `settings.TIME_ZONE = None` is removed as the behavior isn’t commonly used and is questionably useful. If you want to automatically detect the timezone based on the system timezone, you can use tzlocal:

    from tzlocal import get_localzone

    TIME_ZONE = get_localzone().zone

Cela fonctionne comme pour `settings.TIME_ZONE = None` sauf que ça définit aussi `os.environ['TZ']`. Faites nous savoir s’il existe d’après vous une situation où il n’est pas possible d’adapter votre code pour définir un fuseau `TIME_ZONE`.

### Changements HTML dans les gabarits d’administration

`<p class="help">` est remplacé par une balise `<div>` pour permettre d’inclure des listes dans le texte d’aide.

Les champs en lecture seule sont enveloppés par `<div class="readonly">...</div>` au lieu de `<p>...</p>` pour permettre d’inclure tout code HTML dans le contenu du champ.

### Changements dus à l’introduction du rendu des composants HTML sur la base de gabarits

Certaines classes non documentées dans `django.forms.widgets` sont supprimées :

- `SubWidget`
- `RendererMixin`, `ChoiceFieldRenderer`, `RadioFieldRenderer`, `CheckboxFieldRenderer`
- `ChoiceInput`, `RadioChoiceInput`, `CheckboxChoiceInput`

The undocumented `Select.render_option()` method is removed.

La méthode `Widget.format_output()` est supprimée. Utilisez à la place un gabarit de composant personnalisé.

Certaines valeurs de composants, telles que les options `<select>` sont dorénavant régionalisées quand `settings.USE_L10N=True`. Vous pouvez revenir à l’ancien comportement avec des gabarits de composants personnalisés utilisant la balise de gabarit `localize` afin de désactiver la régionalisation.

### `django.template.backends.django.Template.render()` interdit les contextes non dictionnaires

Par compatibilité avec les configurations ayant plusieurs moteurs de gabarits, `django.template.backends.django.Template.render()` (renvoyé par les API de chargement de gabarit de haut niveau comme par `loader.get_template()`) doit recevoir un dictionnaire comme contexte plutôt que des classes `Context` ou `RequestContext`. Si vous transmettiez l’une de ces classes, transmettez plutôt un dictionnaire, ce qui reste compatible avec les anciennes versions de Django.

### Modifications des états de modèles dans les opérations de migration

Pour améliorer la rapidité d’application des migrations, le rendu des modèles liés est différé jusqu’à l’opération qui doit les utiliser (par ex. `RunPython`). Si vous avez une opération personnalisée qui fonctionne avec des classes ou instances de modèles à partir du paramètre `from_state` dans `database_forwards()` ou `database_backwards()`, il faut produire les états de modèles en utilisant la méthode `clear_delayed_apps_cache()` comme expliqué dans écrire ses propres opérations de migration.

### Server-side cursors on PostgreSQL

The change to make `QuerySet.iterator()` use server-side cursors on PostgreSQL prevents running Django with PgBouncer in transaction pooling mode. To reallow that, use the `DISABLE_SERVER_SIDE_CURSORS` setting (added in Django 1.11.1) in `DATABASES`.

See Transactions groupées et curseurs côté serveur for more discussion.

### Divers

- Si aucun élément d’un flux ne possède d’attribut `pubdate` ou `updateddate`, `SyndicationFeed.latest_post_date()` renvoie dorénavant la date/heure actuelle en UTC au lieu d’une date/heure naïve sans fuseau horaire.

- Les échecs CSRF sont journalisés dans le journaliseur `django.security.csrf` au lieu de `django.request`.

- La validation `ALLOWED_HOSTS` n’est plus désactivée lors du lancement des tests. Si votre application inclut des tests avec des noms d’hôte personnalisés, vous devez inclure ces noms dans `ALLOWED_HOSTS`. Voir Tests avec plusieurs noms d’hôtes.

- L’utilisation d’un identifiant de clé étrangère (par ex. `'field_id'`) dans `ModelAdmin.list_display` affiche l’ID de l’objet lié. Enlevez le suffixe `_id` si vous souhaitez l’ancien comportement de la représentation textuelle de l’objet.

- Dans les formulaires de modèles, `CharField` avec `null=True` enregistre dorénavant des valeurs `NULL` lors de saisies vierges au lieu de chaînes vides.

- Avec Oracle, `Model.validate_unique()` ne vérifie plus l’unicité des chaînes vides dans la mesure où la base de données interprète la valeur comme `NULL`.

- Si vous héritez de `AbstractUser` et que vous surchargez `clean()`, assurez-vous d’appeler `super()`. `BaseUserManager.normalize_email()` est appelée dans une nouvelle méthode `AbstractUser.clean()` afin que la normalisation soit appliquée dans des situations comme la validation des modèles de formulaires.

- `EmailField` et `URLField` n’acceptent plus le paramètre nommé `strip`. Il a été enlevé car il n’a aucun effet dans les anciennes versions de Django dans la mesure où ces champs enlèvent systématiquement les espaces de début et de fin.

- Les attributs `checked` et `selected` produits par les composants de formulaires utilisent dorénavant la syntaxe booléenne de HTML 5 au lieu de la syntaxe `checked="checked"` et `selected='selected'` de XHTML.

- `RelatedManager.add()`, `remove()`, `clear()` et `set()` effacent dorénavant le cache `prefetch_related()`.

- Pour éviter la perte possible de réglages enregistrés, `setup_test_environment()` génère dorénavant une exception si elle est appelée une seconde fois avant d’appeler `teardown_test_environment()`.

- L’alias non documenté `DateTimeAwareJSONEncoder` de `DjangoJSONEncoder` (renommé dans Django 1.0) a été supprimé.

- The `cached template loader` is now enabled if `OPTIONS['loaders']` isn’t specified and `OPTIONS['debug']` is `False` (the latter option defaults to the value of `DEBUG`). This could be backwards-incompatible if you have some template tags that aren’t thread safe.

- L’invitation à supprimer les types de contenus périmés n’intervient plus après le lancement de la commande `migrate`. Utilisez plutôt la nouvelle commande `remove_stale_contenttypes`.

- Le composant de formulaire d’administration pour `IntegerField` utilise `type="number"` au lieu de `type="text"`.

- Les en-têtes HTTP conditionnels sont dorénavant analysés et comparés en accord avec la spécification des requêtes conditionnelles RFC 7232 plutôt que l’ancienne RFC 2616.

- `patch_response_headers()` n’ajoute plus d’en-tête `Last-Modified`. En accord avec la RFC 7234#section-4.2.2, cet en-tête est inutile lorsque d’autres en-têtes de cache fournissant une date d’expiration explicite sont présents, comme `Expires` ou `Cache-Control`. `UpdateCacheMiddleware` et `add_never_cache_headers()` appellent `patch_response_headers()` et sont donc également touchés par ce changement.

- Dans les gabarits d’administration, `<p class="help">` est remplacé par une balise `<div>` pour permettre d’inclure des listes dans le texte d’aide.

- `ConditionalGetMiddleware` ne définit plus l’en-tête `Date` car ce sont les serveurs Web qui le définissent. L’en-tête `Content-Length` n’est lui aussi plus défini par cet intergiciel car cette tâche est dévolue à `CommonMiddleware`.

  If you have a middleware that modifies a response’s content and appears before `CommonMiddleware` in the `MIDDLEWARE` or `MIDDLEWARE_CLASSES` settings, you must reorder your middleware so that responses aren’t modified after `Content-Length` is set, or have the response modifying middleware reset the `Content-Length` header.

- `get_model()` et `get_models()` produisent l’erreur `AppRegistryNotReady` s’ils sont appelés avant que les modèles de toutes les applications aient été chargés. Précédemment, ils n’exigeaient que le chargement des modèles de l’application cible, ce qui pouvait renvoyer des modèles dont certaines relations n’étaient pas encore définies. Si vous avez absolument besoin de l’ancien comportement de `get_model()`, définissez le paramètre `require_ready` à `False`.

- L’attribut non utilisé `BaseCommand.can_import_settings` a été supprimé.

- Le décorateur non documenté `django.utils.functional.lazy_property` a été supprimé.

- Par cohérence avec les requêtes sans parties multiples, `MultiPartParser.parse()` définit dorénavant `request.POST` comme non modifiable. Si vous devez modifier cette structure `QueryDict`, vous devez la copier préalablement, par exemple avec `request.POST.copy()`.

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

- La prise en charge de IPython < 1.0 a été abandonnée dans la commande `shell`.

- The signature of private API `Widget.build_attrs()` changed from `extra_attrs=None, **kwargs` to `base_attrs, extra_attrs=None`.

- File-like objects (e.g., `StringIO` and `BytesIO`) uploaded to an `ImageField` using the test client now require a `name` attribute with a value that passes the `validate_image_file_extension` validator. See the note in `Client.post()`.

- `FileField` now moves rather than copies the file it receives. With the default file upload settings, files larger than `FILE_UPLOAD_MAX_MEMORY_SIZE` now have the same permissions as temporary files (often `0o600`) rather than the system’s standard umask (often `0o6644`). Set the `FILE_UPLOAD_PERMISSIONS` if you need the same permission regardless of file size.

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

### Le décorateur `models.permalink()`

Utilisez `django.urls.reverse()` à la place. Par exemple :

    from django.db import models

    class MyModel(models.Model):
        ...

        @models.permalink
        def url(self):
            return ('guitarist_detail', [self.slug])

devient :

    from django.db import models
    from django.urls import reverse

    class MyModel(models.Model):
        ...

        def url(self):
            return reverse('guitarist_detail', args=[self.slug])

### Divers

- Les vues fonctions `login()` et `logout()` de `contrib.auth` ont été rendues obsolètes en faveur des nouvelles fonctions classes `LoginView` et `LogoutView`.
- Le paramètre inutilisé `extra_context` de `contrib.auth.views.logout_then_login()` est obsolète.
- Les vues fonctions `password_change()`, `password_change_done()`, `password_reset()`, `password_reset_done()`, `password_reset_confirm()` et `password_reset_complete()` de `contrib.auth` ont été rendues obsolètes en faveur des nouvelles vues classes `PasswordChangeView`, `PasswordChangeDoneView`, `PasswordResetView`, `PasswordResetDoneView`, `PasswordResetConfirmView` et `PasswordResetCompleteView`.
- `django.test.runner.setup_databases()` a été déplacé dans `django.test.utils.setup_databases()`. L’ancien emplacement est obsolète.
- `django.utils.translation.string_concat()` a été rendue obsolète en faveur de `django.utils.text.format_lazy()`. `string_concat(*strings)` peut être remplacé par `format_lazy('{}' * len(strings), *strings)`.
- Pour le moteur de cache `PyLibMCCache`, la transmission de réglages de comportement `pylibmc` comme attribut de premier niveau dans `OPTIONS` est obsolète. Définissez plutôt ces réglages sous une clé `behaviors` dans `OPTIONS`.
- Le paramètre `host` de `django.utils.http.is_safe_url()` a été rendu obsolète en faveur du nouveau paramètre `allowed_hosts`.
- Le masquage des exceptions produites lors du rendu de la balise de gabarit `{% include %}` est obsolète car ce comportement prêtait parfois à confusion. Avec Django 2.1, les exceptions seront propagées.
- `DatabaseIntrospection.get_indexes()` a été rendue obsolète en faveur de `DatabaseIntrospection.get_constraints()`.
- `authenticate()` transmet dorénavant un paramètre `request` à la méthode `authenticate()` des moteurs d’authentification. La prise en charge des méthodes qui n’acceptent pas `request` comme premier paramètre de position sera supprimée dans Django 2.1.
- Le réglage `USE_ETAGS` a été rendu obsolète en faveur de `ConditionalGetMiddleware` qui ajoute désormais l’en-tête `ETag` aux réponses sans tenir compte du réglage. `CommonMiddleware` et `django.utils.cache.patch_response_headers()` ne définiront plus d’en-tête `ETag` à la fin de la période d’obsolescence.
- `Model._meta.has_auto_field` a été rendu obsolète en faveur du contrôle `Model._meta.auto_field is not None`.
- L’emploi de groupes d’expression régulière avec `iLmsu#` dans `url()` est obsolète. Le seul groupe utile est `(?i)` pour les URL non sensibles à la casse ; toutefois, ces URL ne sont pas à encourager car ils créent des entrées multiples pour les moteurs de recherche, par exemple. Une solution alternative pourrait être de créer une fonction `handler404` à la recherche de caractères majuscules dans l’URL et redirigeant vers l’équivalent en minuscules.
- Le paramètre `renderer` a été ajouté à la méthode `Widget.render()`. Les méthodes qui n’acceptent pas ce paramètre fonctionneront encore le temps de la période d’obsolescence.