# Documentation Django 3.1.9.dev

# Notes de publication de Django 1.10

1er août 2016

Bienvenue dans Django 1.10 !

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

Comme pour Django 1.9, Django 1.10 requiert Python 2.7, 3.4 ou 3.5. Nous recommandons vivement et nous ne prenons officiellement en charge que la dernière publication de chaque série.

## Quoi de neuf dans Django 1.10

### Recherche plein texte avec PostgreSQL

`django.contrib.postgres` inclut dorénavant une série de fonctions de base de données permettant d’exploiter le moteur de recherche plein texte. IL est possible de rechercher dans plusieurs champs de la base de données relationnelle, de combiner les recherches avec d’autres expressions de requête, d’utiliser différentes configurations de langue et de pondération, ainsi que de classer les résultats par pertinence.

Elle inclut aussi la prise en charge des trigrammes, en utilisant la requête `trigram_similar` et les expressions `TrigramSimilarity` et `TrigramDistance`.

### Intergiciels nouveau style

A new style of middleware is introduced to solve the lack of strict request/response layering of the old-style of middleware described in DEP 0005. You’ll need to adapt old, custom middleware and switch from the `MIDDLEWARE_CLASSES` setting to the new `MIDDLEWARE` setting to take advantage of the improvements.

### Prise en charge officielle des noms d’utilisateurs Unicode

The `User` model in `django.contrib.auth` originally only accepted ASCII letters and numbers in usernames. Although it wasn’t a deliberate choice, Unicode characters have always been accepted when using Python 3.

The username validator now explicitly accepts Unicode characters by default on Python 3 only.

Custom user models may use the new `ASCIIUsernameValidator` or `UnicodeUsernameValidator`.

### Fonctionnalités mineures

#### `django.contrib.admin`

- Pour les sites fonctionnant dans un sous-chemin, `l'URL par défaut du lien « Voir sur le site »` au sommet de chaque page du site d’administration prend désormais en compte `request.META['SCRIPT_NAME']` s’il est défini au lieu de `/`.
- Le message de succès apparaissant après l’ajout ou l’édition d’un objet contient maintenant un lien vers le formulaire de modification de l’objet concerné.
- Tout le code JavaScript en ligne a été enlevé afin de pouvoir activer l’en-tête HTTP `Content-Security-Policy` si souhaité.
- Le nouvel attribut `InlineModelAdmin.classes` permet d’indiquer des classes pour les sous-formulaires en ligne. Ces derniers, s’ils possèdent une classe `collapse`, sont initialement repliés et leur en-tête contient un petit lien « Afficher ».
- If a user doesn’t have the add permission, the `object-tools` block on a model’s changelist will now be rendered (without the add button). This makes it easier to add custom tools in this case.
- Le modèle `LogEntry` stocke dorénavant ses messages de modification dans une structure JSON afin que les messages puissent être dynamiquement traduits dans la langue active. Une nouvelle méthode `LogEntry.get_change_message()` constitue maintenant la manière privilégiée d’obtenir les messages de modification.
- Les objets sélectionnés pour les champs dans `ModelAdmin.raw_id_fields` ont maintenant un lien vers le formulaire de modification des objets.
- Les choix « Aucune date » et « Possède une date » on été ajoutés pour le filtre `DateFieldListFilter` dans le cas où le champ peut contenir la valeur nulle.
- La bibliothèque jQuery incluse dans l’administration a été mise à jour de 2.1.4 vers 2.2.3.

#### `django.contrib.auth`

- La prise en charge du hachage de mot de passe Argon2 a été ajoutée. Il devrait être préféré à PBKDF2, mais il n’est cependant pas par défaut car il nécessite une bibliothèque tierce.
- Le nombre d’itérations par défaut du hachage des mots de passe PBKDF2 a été augmenté de 25%. Cette modification rétrocompatible n’affecte pas ceux qui ont créé une sous-classe de `django.contrib.auth.hashers.PBKDF2PasswordHasher` pour modifier la valeur par défaut.
- The `django.contrib.auth.views.logout()` view sends « no-cache » headers to prevent an issue where Safari caches redirects and prevents a user from being able to log out.
- Added the optional `backend` argument to `django.contrib.auth.login()` to allow using it without credentials.
- The new `LOGOUT_REDIRECT_URL` setting controls the redirect of the `django.contrib.auth.views.logout()` view, if the view doesn’t get a `next_page` argument.
- The new `redirect_authenticated_user` parameter for the `django.contrib.auth.views.login()` view allows redirecting authenticated users visiting the login page.
- Les nouveaux moteurs d’authentification `AllowAllUsersModelBackend` et `AllowAllUsersRemoteUserBackend` ignorent la valeur de `User.is_active`, alors que `ModelBackend` et `RemoteUserBackend` rejettent dorénavant les utilisateurs inactifs.

#### `django.contrib.gis`

- Les requêtes de distance acceptent maintenant des expressions comme paramètre de valeur de distance.
- La nouvelle propriété `GEOSGeometry.unary_union` calcule l’union de tous les éléments d’un objet géométrique.
- Le prédicat binaire `GEOSGeometry.covers()` a été ajouté.
- La méthode `GDALBand.statistics()` ainsi que les attributs `mean` et `std` ont été ajoutés.
- L’agrégat `MakeLine` et la fonction `GeoHash` ont été ajoutés pour Spatialite.
- Les fonctions `Difference`, `Intersection` et `SymDifference` ont été ajoutées pour MySQL.
- La possibilité d’instancier des géométries GEOS vides a été ajoutée.
- Les nouvelles propriétés `trim` et `precision` de `WKTWriter` permettent de contrôler la précision de la partie fractionnelle des coordonnées produites au format WKT.
- Les propriétés `LineString.closed` et `MultiLineString.closed` ont été ajoutées.
- Le sérialiseur GeoJSON produit dorénavant la clé primaire des objets dans le dictionnaire `properties` si aucun champ spécifique n’est indiqué.
- La possibilité de dupliquer des données d’entrées de la méthode `GDALBand.data()` a été ajoutée. Les données de bande peuvent maintenant être mises à jour efficacement avec des valeurs répétées.
- Les fonctions de base de données `IsValid` et `MakeValid` ont été ajoutées, de même que la requête `isvalid`, le tout pour PostGIS. Cela permet de filtrer et de réparer des objets géométriques non valides du côté de la base de données.
- La prise en charge des objets matriciels (raster) a été ajoutée pour toutes les requêtes spatiales.

#### `django.contrib.postgres`

- Par commodité, `HStoreField` force dorénavant ses clés et valeurs en texte.

#### `django.contrib.sessions`

- La commande d’administration `clearsessions` supprime dorénavant les sessions basées sur des fichiers.

#### `django.contrib.sites`

- Le modèle `Site` prend dorénavant en charge les clés naturelles.

#### `django.contrib.staticfiles`

- La balise de gabarit `static` utilise maintenant `django.contrib.staticfiles` si cette application est installée. C’est particulièrement utile pour les applications tierces qui peuvent dorénavant toujours utiliser `{% load static %}` (au lieu de `{% load staticfiles %}` ou `{% load static from staticfiles %}`) et ne plus se soucier de savoir si l’application `staticfiles` est installée ou non.
- You can more easily customize the `collectstatic --ignore` option with a custom `AppConfig`.

#### Cache

- Le moteur de cache basé sur des fichiers utilise dorénavant le protocole de « pickling » le plus élevé.

#### CSRF

- La vue par défaut `CSRF_FAILURE_VIEW`, `views.csrf.csrf_failure()`, accepte dorénavant un paramètre facultatif `template_name`, valant `'403_csrf.html'` par défaut, pour contrôler le gabarit utilisé pour produire la page.
- Afin de protéger contre les attaques BREACH, le mécanisme de protection CSRF modifie dorénavant la valeur du jeton de formulaire lors de chaque requête (tout en conservant une valeur secrète stable pouvant être utilisée pour valider les différents jetons).

#### Moteurs de base de données

- La soustraction de données temporelles a été unifiée pour tous les moteurs.
- Si la base de données le gère, les moteurs peuvent définir `DatabaseFeatures.can_return_ids_from_bulk_insert=True` et implémenter `DatabaseOperations.fetch_returned_insert_ids()` pour définir les clés primaires des objets créés par `QuerySet.bulk_create()`.
- Des paramètres nommés ont été ajoutés aux méthodes `as_sql()` de diverses expressions (`Func`, `When`, `Case` et `OrderBy`) pour permettre aux moteurs de base de données de les personnaliser sans devoir toucher à `self`, ce qui est peu sûr lors de l’emploi de plusieurs moteurs de base de données. Voir les paramètres `arg_joiner` et `**extra_context` de `Func.as_sql()` pour un exemple.

#### Stockage de fichier

- Les moteurs de stockage présentent dorénavant une API consciente du fuseau horaire avec de nouvelles méthodes `get_accessed_time()`, `get_created_time()` et `get_modified_time()`. Elles renvoient un objet `datetime` conscient du fuseau horaire si `USE_TZ` vaut `True` et un objet `datetime` « naïf » dans le fuseau horaire local dans le cas contraire.
- La nouvelle méthode `Storage.generate_filename()` facilite l’implémentation de stockages personnalisés qui n’utilisent pas les appels `os.path` qui se trouvaient précédemment dans `FileField`.

#### Formulaires

- Les contenus de la classe `Media` des formulaires et composants sont dorénavant servis par `django.contrib.staticfiles` quand cette application est installée.
- La balise `<input>` rendue par `CharField` inclut maintenant un attribut `minlength` si le champ possède un attribut `min_length`.
- Les champs de formulaire obligatoires possèdent dorénavant l’attribut HTML `required`. Il est possible de désactiver cela en définissant l’attribut `Form.use_required_attribute` à `False`. L’attribut `required` n’est pas ajouté aux formulaires groupés car la validation des navigateurs n’est pas toujours correcte quand on ajoute ou qu’on supprime de tels formulaires.

#### Vues génériques

- La classe `View` peut dorénavant être importée depuis `django.views`.

#### Internationalisation

- La fonction utilitaire `i18n_patterns()` peut dorénavant être utilisée dans une configuration d’URL racine désignée par `request.urlconf`.
- En définissant le nouveau paramètre `prefix_default_language` de `i18n_patterns()` à `False`, vous pouvez autoriser l’accès à la langue par défaut sans préfixe d’URL.
- `set_language()` renvoie désormais un code de statut 204 (Pas de contenu) pour les requêtes AJAX lorsque `POST` ou `GET` ne contiennent pas de paramètre `next`.
- Les vues fondées sur des classes `JavaScriptCatalog` et `JSONCatalog` remplacent les vues fondées sur des fonctions `javascript_catalog()` et `json_catalog()`. Les nouvelles vues sont presque équivalentes aux anciennes sauf que par défaut les nouvelles vues collectent toutes les chaînes JavaScript de toutes les applications installées dans le domaine de traduction `djangojs` au lieu de seulement récolter les chaînes JavaScript provenant des chemins `LOCALE_PATHS`.

#### Commandes d’administration

- `call_command()` renvoie dorénavant la valeur reçue de la méthode `command.handle()`.
- La nouvelle option `check --fail-level` permet de définir le niveau de message qui produira la sortie de la commande avec un code d’état différent de zéro.
- La nouvelle option `makemigrations --check` fait quitter la commande avec un statut différent de 0 lorsque des modifications de modèles sans migration correspondante sont détectés.
- `makemigrations` affiche dorénavant le chemin vers les fichiers de migration qu’elle génère.
- L’option `shell --interface` accepte dorénavant `python` pour forcer l’utilisation de l’interpréteur Python « pur ».
- La nouvelle option `shell --command` permet d’exécuter une commande depuis Django et quitter, au lieu d’ouvrir le shell interactif.
- `dumpdata` émet un avertissement si un modèle mandataire est spécifié (qui ne produit aucun résultat) sans son parent concret.
- Le nouvel attribut `BaseCommand.requires_migrations_checks` peut être défini à `True` si vous souhaitez que la commande affiche un avertissement, comme le fait `runserver`, quand le jeu de migrations sur disque ne correspond pas aux migrations dans la base de données.
- Pour aider dans les tests, `call_command()` accepte dorénavant un objet commande comme premier paramètre.
- The `shell` command supports tab completion on systems using `libedit`, e.g. macOS.
- La commande `inspectdb` permet de choisir les tables à inspecter en indiquant leur nom en paramètre.

#### Migrations

- La prise en charge de la sérialisation d’objets `enum.Enum` a été ajoutée.
- Le paramètre `elidable` a été ajouté aux opérations `RunSQL` et `RunPython` pour indiquer qu’elles doivent être supprimées lors de la fusion des migrations.
- La prise en charge des migrations non atomiques a été ajoutée en définissant l’attribut `atomic` d’une classe `Migration`.
- The `migrate` and `makemigrations` commands now check for a consistent migration history. If they find some unapplied dependencies of an applied migration, `InconsistentMigrationHistory` is raised.
- Les signaux `pre_migrate()` et `post_migrate()` propagent dorénavant le `plan` et les `apps` de la migration.

#### Modèles

- Les clés étrangères inverses de modèles mandataires sont dorénavant propagées vers leur classe concrète. La relation inverse liée par une clé `ForeignKey` pointant vers un modèle mandataire est dorénavant accessible sous forme de descripteur sur la classe de modèle mandatée et peut être référencée dans des filtres de requête.
- La nouvelle méthode `Field.rel_db_type()` renvoie le type de donnée de la colonne de la base de données, tel que `ForeignKey` et `OneToOneField` qui pointent vers un autre champ.
- L’attribut de classe `arity` a été ajouté à `Func`. Cet attribut est utilisé pour définir le nombre de paramètres acceptés par la fonction.
- Le nouveau champ `BigAutoField` est très similaire à `AutoField` sauf qu’il garantit la couverture des nombres de `1` à `9223372036854775807`.
- `QuerySet.in_bulk()` peut être appelée sans paramètre pour renvoyer tous les objets du jeu de requête.
- `related_query_name` prend désormais en charge l’extrapolation de l’étiquette d’application et de la classe en utilisant les chaînes `'%(app_label)s'` et `'%(class)s'`.
- Il est dorénavant autorisé de surcharger des champs de modèles hérités de classes de base abstraites.
- La fonction `prefetch_related_objects()` est maintenant une API publique.
- `QuerySet.bulk_create()` définit la clé primaire des objets quand on l’utilise avec PostgreSQL.
- La fonction de base de données `Cast` a été ajoutée.
- Un modèle mandataire peut dorénavant hériter de plusieurs modèles mandataires partageant une classe parente commune non abstraite.
- Added `Extract` functions to extract datetime components as integers, such as year and hour.
- Added `Trunc` functions to truncate a date or datetime to a significant component. They enable queries like sales-per-day or sales-per-hour.
- `Model.__init__()` définit dorénavant les valeurs de champs virtuels à partir de ses paramètres nommés.
- Les nouvelles options `Meta.base_manager_name` et `Meta.default_manager_name` permettent de contrôler respectivement les attributs `_base_manager` et `_default_manager`.

#### Requêtes et réponses

- `request.user` a été ajoutée à la vue de débogage.
- Les méthodes `readable()` et `seekable()` ont été ajoutées à `HttpResponse` pour en faire une instance d’objet de type flux et permettre de l’adapter dans une classe `io.TextIOWrapper`.
- Added the `HttpRequest.content_type` and `content_params` attributes which are parsed from the `CONTENT_TYPE` header.
- L’analyseur de `request.COOKIES` a été simplifié pour mieux correspondre au comportement des navigateurs. `request.COOKIES` peut dorénavant contenir des cookies non valides selon la RFC 6265 mais qui peuvent quand même être définis via `document.cookie`.

#### Sérialisation

- `django.core.serializers.json.DjangoJSONEncoder` sait dorénavant sérialiser des chaînes différées, typiquement utilisées pour du contenu traduisible.

#### Gabarits

- L’option `autoescape` a été ajoutée au moteur `DjangoTemplates` et à la classe `Engine`.
- Les opérateurs de comparaison `is` et `is not` ont été ajoutée à la balise `if`.
- `dictsort` peut maintenant trier une liste de listes par un élément d’un indice donné.
- Le processeur de contexte `debug()` contient les requêtes de tous les alias de base de données, et non plus seulement celles de l’alias par défaut.
- Les balises de gabarit `extends` et `include` prennent dorénavant en charge des chemins relatifs pour leurs paramètres sous forme de chaîne.

#### Tests

- Pour mieux éviter les bugs, `TestCase` contrôle dorénavant les contraintes de base de données différables à la fin de chaque test.
- Les tests et les cas de test peuvent être marqués par des étiquettes et exécutés de manière sélective grâce aux nouvelles options `test --tag` et `test --exclude-tag`.
- Il est maintenant possible de se connecter et d’utiliser des sessions avec le client de test même si `django.contrib.sessions` ne se trouve pas dans `INSTALLED_APPS`.

#### URL

- Un ajout à `django.setup()` permet à la résolution d’URL qui intervient en dehors du cycle requête/réponse (par ex. dans les commandes d’administration et les scripts autonomes) de prendre en compte `FORCE_SCRIPT_NAME` lorsque celui-ci est défini.

#### Validateurs

- `URLValidator` limite dorénavant la longueur des parties de noms de domaine à 63 caractères et la longueur totale des noms de domaines à 253 caractères, en accord avec la RFC 1034.
- `int_list_validator()` accepte dorénavant un paramètre booléen facultatif `allow_negative`, valant `False` par défaut, pour autoriser les entiers négatifs.

## Changements incompatibles avec les anciennes versions dans Django 1.10

Avertissement

En plus des modifications détaillées dans cette section, prenez soin de parcourir les Fonctionnalités supprimées dans 1.10 énumérant les fonctionnalités ayant terminé leur cycle d’obsolescence et qui ont donc été supprimées. Si vous n’avez pas mis à jour votre code dans le temps imparti par la période d’obsolescence d’une certaine fonctionnalité, sa suppression pourrait apparaître comme un changement incompatible avec les anciennes versions.

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

- Le champ GIS `AreaField` utilise un type numérique non spécifié qui pourrait être en pratique tout type numérique Python. Les valeurs `decimal.Decimal` provenant de la base de données sont dorénavant converties en `float` pour faciliter leur combinaison avec des valeurs utilisées par les bibliothèques GIS.
- In order to enable temporal subtraction you must set the `supports_temporal_subtraction` database feature flag to `True` and implement the `DatabaseOperations.subtract_temporals()` method. This method should return the SQL and parameters required to compute the difference in microseconds between the `lhs` and `rhs` arguments in the datatype used to store `DurationField`.

### `select_related()` prohibits non-relational fields for nested relations

Django 1.8 added validation for non-relational fields in `select_related()`:

    >>> Book.objects.select_related('title')
    Traceback (most recent call last):
    ...
    FieldError: Non-relational field given in select_related: 'title'

But it didn’t prohibit nested non-relation fields as it does now:

    >>> Book.objects.select_related('author__name')
    Traceback (most recent call last):
    ...
    FieldError: Non-relational field given in select_related: 'name'

### `_meta.get_fields()` returns consistent reverse fields for proxy models

Before Django 1.10, the `get_fields()` method returned different reverse fields when called on a proxy model compared to its proxied concrete class. This inconsistency was fixed by returning the full set of fields pointing to a concrete class or one of its proxies in both cases.

### `AbstractUser.username` `max_length` increased to 150

A migration for `django.contrib.auth.models.User.username` is included. If you have a custom user model inheriting from `AbstractUser`, you’ll need to generate and apply a database migration for your user model.

We considered an increase to 254 characters to more easily allow the use of email addresses (which are limited to 254 characters) as usernames but rejected it due to a MySQL limitation. When using the `utf8mb4` encoding (recommended for proper Unicode support), MySQL can only create unique indexes with 191 characters by default. Therefore, if you need a longer length, please use a custom user model.

If you want to preserve the 30 character limit for usernames, use a custom form when creating a user or changing usernames:

    from django.contrib.auth.forms import UserCreationForm

    class MyUserCreationForm(UserCreationForm):
        username = forms.CharField(
            max_length=30,
            help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.',
        )

If you wish to keep this restriction in the admin, set `UserAdmin.add_form` to use this form:

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

    class UserAdmin(BaseUserAdmin):
        add_form = MyUserCreationForm

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

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

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

### La sortie de `runserver` passe par l’infrastructure de journalisation

Request and response handling of the `runserver` command is sent to the django.server logger instead of to `sys.stderr`. If you disable Django’s logging configuration or override it with your own, you’ll need to add the appropriate logging configuration if you want to see that output:

    'formatters': {
        'django.server': {
            '()': 'django.utils.log.ServerFormatter',
            'format': '[%(server_time)s] %(message)s',
        }
    },
    'handlers': {
        'django.server': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'django.server',
        },
    },
    'loggers': {
        'django.server': {
            'handlers': ['django.server'],
            'level': 'INFO',
            'propagate': False,
        }
    }

### `auth.CustomUser` and `auth.ExtensionUser` test models were removed

Since the introduction of migrations for the contrib apps in Django 1.8, the tables of these custom user test models were not created anymore making them unusable in a testing context.

### Apps registry is no longer auto-populated when unpickling models outside of Django

The apps registry is no longer auto-populated when unpickling models. This was added in Django 1.7.2 as an attempt to allow unpickling models outside of Django, such as in an RQ worker, without calling `django.setup()`, but it creates the possibility of a deadlock. To adapt your code in the case of RQ, you can provide your own worker script that calls `django.setup()`.

### Removed null assignment check for non-null foreign key fields

In older versions, assigning `None` to a non-nullable `ForeignKey` or `OneToOneField` raised `ValueError('Cannot assign None: "model.field" does not allow null values.')`. For consistency with other model fields which don’t have a similar check, this check is removed.

### Removed weak password hashers from the default `PASSWORD_HASHERS` setting

Django 0.90 stored passwords as unsalted MD5. Django 0.91 added support for salted SHA1 with automatic upgrade of passwords when a user logs in. Django 1.4 added PBKDF2 as the default password hasher.

If you have an old Django project with MD5 or SHA1 (even salted) encoded passwords, be aware that these can be cracked fairly easily with today’s hardware. To make Django users acknowledge continued use of weak hashers, the following hashers are removed from the default `PASSWORD_HASHERS` setting:

    'django.contrib.auth.hashers.SHA1PasswordHasher'
    'django.contrib.auth.hashers.MD5PasswordHasher'
    'django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher'
    'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher'
    'django.contrib.auth.hashers.CryptPasswordHasher'

Consider using a wrapped password hasher to strengthen the hashes in your database. If that’s not feasible, add the `PASSWORD_HASHERS` setting to your project and add back any hashers that you need.

You can check if your database has any of the removed hashers like this:

    from django.contrib.auth import get_user_model
    User = get_user_model()

    # Unsalted MD5/SHA1:
    User.objects.filter(password__startswith='md5$$')
    User.objects.filter(password__startswith='sha1$$')
    # Salted MD5/SHA1:
    User.objects.filter(password__startswith='md5$').exclude(password__startswith='md5$$')
    User.objects.filter(password__startswith='sha1$').exclude(password__startswith='sha1$$')
    # Crypt hasher:
    User.objects.filter(password__startswith='crypt$$')

    from django.db.models import CharField
    from django.db.models.functions import Length
    CharField.register_lookup(Length)
    # Unsalted MD5 passwords might not have an 'md5$$' prefix:
    User.objects.filter(password__length=32)

### `Field.get_prep_lookup()` and `Field.get_db_prep_lookup()` methods are removed

If you have a custom field that implements either of these methods, register a custom lookup for it. For example:

    from django.db.models import Field
    from django.db.models.lookups import Exact

    class MyField(Field):
        ...

    class MyFieldExact(Exact):
        def get_prep_lookup(self):
            # do_custom_stuff_for_myfield
            ....

    MyField.register_lookup(MyFieldExact)

### `django.contrib.gis`

- Support for SpatiaLite < 3.0 and GEOS < 3.3 is dropped.
- The `add_postgis_srs()` backwards compatibility alias for `django.contrib.gis.utils.add_srs_entry()` is removed.
- On Oracle/GIS, the `Area` aggregate function now returns a `float` instead of `decimal.Decimal`. (It’s still wrapped in a measure of square meters.)
- The default `GEOSGeometry` representation (WKT output) is trimmed by default. That is, instead of `POINT (23.0000000000000000 5.5000000000000000)`, you’ll get `POINT (23 5.5)`.

### Maximum size of a request body and the number of GET/POST parameters is limited

Two new settings help mitigate denial-of-service attacks via large requests:

- `DATA_UPLOAD_MAX_MEMORY_SIZE` limits the size that a request body may be. File uploads don’t count towards this limit.
- `DATA_UPLOAD_MAX_NUMBER_FIELDS` limits the number of GET/POST parameters that are parsed.

Applications that receive unusually large form posts may need to tune these settings.

### Divers

- The `repr()` of a `QuerySet` is wrapped in `<QuerySet >` to disambiguate it from a plain list when debugging.
- `utils.version.get_version()` returns PEP 440 compliant release candidate versions (e.g. “1.10rc1” instead of “1.10c1”).
- CSRF token values are now required to be strings of 64 alphanumerics; values of 32 alphanumerics, as set by older versions of Django by default, are automatically replaced by strings of 64 characters. Other values are considered invalid. This should only affect developers or users who replace these tokens.
- The `LOGOUT_URL` setting is removed as Django hasn’t made use of it since pre-1.0. If you use it in your project, you can add it to your project’s settings. The default value was `'/accounts/logout/'`.
- Objects with a `close()` method such as files and generators passed to `HttpResponse` are now closed immediately instead of when the WSGI server calls `close()` on the response.
- A redundant `transaction.atomic()` call in `QuerySet.update_or_create()` is removed. This may affect query counts tested by `TransactionTestCase.assertNumQueries()`.
- Support for `skip_validation` in `BaseCommand.execute(**options)` is removed. Use `skip_checks` (added in Django 1.7) instead.
- `loaddata` now raises a `CommandError` instead of showing a warning when the specified fixture file is not found.
- Instead of directly accessing the `LogEntry.change_message` attribute, it’s now better to call the `LogEntry.get_change_message()` method which will provide the message in the current language.
- The default error views now raise `TemplateDoesNotExist` if a nonexistent `template_name` is specified.
- The unused `choices` keyword argument of the `Select` and `SelectMultiple` widgets” `render()` method is removed. The `choices` argument of the `render_options()` method is also removed, making `selected_choices` the first argument.
- Tests that violate deferrable database constraints will now error when run on a database that supports deferrable constraints.
- Built-in management commands now use indexing of keys in `options`, e.g. `options['verbosity']`, instead of `options.get()` and no longer perform any type coercion. This could be a problem if you’re calling commands using `Command.execute()` (which bypasses the argument parser that sets a default value) instead of `call_command()`. Instead of calling `Command.execute()`, pass the command object as the first argument to `call_command()`.
- `ModelBackend` and `RemoteUserBackend` now reject inactive users. This means that inactive users can’t login and will be logged out if they are switched from `is_active=True` to `False`. If you need the previous behavior, use the new `AllowAllUsersModelBackend` or `AllowAllUsersRemoteUserBackend` in `AUTHENTICATION_BACKENDS` instead.
- In light of the previous change, the test client’s `login()` method no longer always rejects inactive users but instead delegates this decision to the authentication backend. `force_login()` also delegates the decision to the authentication backend, so if you’re using the default backends, you need to use an active user.
- `django.views.i18n.set_language()` may now return a 204 status code for AJAX requests.
- The `base_field` attribute of `RangeField` is now a type of field, not an instance of a field. If you have created a custom subclass of `RangeField`, you should change the `base_field` attribute.
- Middleware classes are now initialized when the server starts rather than during the first request.
- If you override `is_authenticated()` or `is_anonymous()` in a custom user model, you must convert them to attributes or properties as described in the deprecation note.
- When using `ModelAdmin.save_as=True`, the « Save as new » button now redirects to the change view for the new object instead of to the model’s changelist. If you need the previous behavior, set the new `ModelAdmin.save_as_continue` attribute to `False`.
- Required form fields now have the `required` HTML attribute. Set the `Form.use_required_attribute` attribute to `False` to disable it. You could also add the `novalidate` attribute to `<form>` if you don’t want browser validation. To disable the `required` attribute on custom widgets, override the `Widget.use_required_attribute()` method.
- The WSGI handler no longer removes content of responses from `HEAD` requests or responses with a `status_code` of 100-199, 204, or 304. Most Web servers already implement this behavior. Responses retrieved using the Django test client continue to have these « response fixes » applied.
- `Model.__init__()` now receives `django.db.models.DEFERRED` as the value of deferred fields.
- The `Model._deferred` attribute is removed as dynamic model classes when using `QuerySet.defer()` and `only()` is removed.
- `Storage.save()` no longer replaces `'\'` with `'/'`. This behavior is moved to `FileSystemStorage` since this is a storage specific implementation detail. Any Windows user with a custom storage implementation that relies on this behavior will need to implement it in the custom storage’s `save()` method.
- Private `FileField` methods `get_directory_name()` and `get_filename()` are no longer called (and are now deprecated) which is a backwards incompatible change for users overriding those methods on custom fields. To adapt such code, override `FileField.generate_filename()` or `Storage.generate_filename()` instead. It might be possible to use `upload_to` also.
- The subject of mail sent by `AdminEmailHandler` is no longer truncated at 989 characters. If you were counting on a limited length, truncate the subject yourself.
- Private expressions `django.db.models.expressions.Date` and `DateTime` are removed. The new `Trunc` expressions provide the same functionality.
- The `_base_manager` and `_default_manager` attributes are removed from model instances. They remain accessible on the model class.
- Accessing a deleted field on a model instance, e.g. after `del obj.field`, reloads the field’s value instead of raising `AttributeError`.
- If you subclass `AbstractBaseUser` and override `clean()`, be sure it calls `super()`. `AbstractBaseUser.normalize_username()` is called in a new `AbstractBaseUser.clean()` method.
- Private API `django.forms.models.model_to_dict()` returns a queryset rather than a list of primary keys for `ManyToManyField`s.
- If `django.contrib.staticfiles` is installed, the `static` template tag uses the `staticfiles` storage to construct the URL rather than simply joining the value with `STATIC_ROOT`. The new approach encodes the URL, which could be backwards-incompatible in cases such as including a fragment in a path, e.g. `{% static 'img.svg#fragment' %}`, since the `#` is encoded as `%23`. To adapt, move the fragment outside the template tag: `{% static 'img.svg' %}#fragment`.
- When `USE_L10N` is `True`, localization is now applied for the `date` and `time` filters when no format string is specified. The `DATE_FORMAT` and `TIME_FORMAT` specifiers from the active locale are used instead of the settings of the same name.

## Features deprecated in 1.10

### Direct assignment to a reverse foreign key or many-to-many relation

Instead of assigning related objects using direct assignment:

    >>> new_list = [obj1, obj2, obj3]
    >>> e.related_set = new_list

Use the `set()` method added in Django 1.9:

    >>> e.related_set.set([obj1, obj2, obj3])

Cela évite de la confusion concernant l’enregistrement implicite provoqué par l’attribution directe.

### Non-timezone-aware `Storage` API

The old, non-timezone-aware methods `accessed_time()`, `created_time()`, and `modified_time()` are deprecated in favor of the new `get_*_time()` methods.

Third-party storage backends should implement the new methods and mark the old ones as deprecated. Until then, the new `get_*_time()` methods on the base `Storage` class convert `datetime`s from the old methods as required and emit a deprecation warning as they do so.

Third-party storage backends may retain the old methods as long as they wish to support earlier versions of Django.

### `django.contrib.gis`

- The `get_srid()` and `set_srid()` methods of `GEOSGeometry` are deprecated in favor of the `srid` property.
- The `get_x()`, `set_x()`, `get_y()`, `set_y()`, `get_z()`, and `set_z()` methods of `Point` are deprecated in favor of the `x`, `y`, and `z` properties.
- The `get_coords()` and `set_coords()` methods of `Point` are deprecated in favor of the `tuple` property.
- The `cascaded_union` property of `MultiPolygon` is deprecated in favor of the `unary_union` property.
- The `django.contrib.gis.utils.precision_wkt()` function is deprecated in favor of `WKTWriter`.

### `CommaSeparatedIntegerField` model field

`CommaSeparatedIntegerField` is deprecated in favor of `CharField` with the `validate_comma_separated_integer_list()` validator:

    from django.core.validators import validate_comma_separated_integer_list
    from django.db import models

    class MyModel(models.Model):
        numbers = models.CharField(..., validators=[validate_comma_separated_integer_list])

If you’re using Oracle, `CharField` uses a different database field type (`NVARCHAR2`) than `CommaSeparatedIntegerField` (`VARCHAR2`). Depending on your database settings, this might imply a different encoding, and thus a different length (in bytes) for the same contents. If your stored values are longer than the 4000 byte limit of `NVARCHAR2`, you should use `TextField` (`NCLOB`) instead. In this case, if you have any queries that group by the field (e.g. annotating the model with an aggregation or using `distinct()`) you’ll need to change them (to defer the field).

### Using a model name as a query lookup when `default_related_name` is set

Assume the following models:

    from django.db import models

    class Foo(models.Model):
        pass

    class Bar(models.Model):
        foo = models.ForeignKey(Foo)

        class Meta:
            default_related_name = 'bars'

In older versions, `default_related_name` couldn’t be used as a query lookup. This is fixed and support for the old lookup name is deprecated. For example, since `default_related_name` is set in model `Bar`, instead of using the model name `bar` as the lookup:

    >>> bar = Bar.objects.get(pk=1)
    >>> Foo.objects.get(bar=bar)

use the default_related_name `bars`:

    >>> Foo.objects.get(bars=bar)

### `__search` query lookup

The `search` lookup, which supports MySQL only and is extremely limited in features, is deprecated. Replace it with a custom lookup:

    from django.db import models

    class Search(models.Lookup):
        lookup_name = 'search'

        def as_mysql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return 'MATCH (%s) AGAINST (%s IN BOOLEAN MODE)' % (lhs, rhs), params

    models.CharField.register_lookup(Search)
    models.TextField.register_lookup(Search)

### Using `User.is_authenticated()` and `User.is_anonymous()` as methods

The `is_authenticated()` and `is_anonymous()` methods of `AbstractBaseUser` and `AnonymousUser` classes are now properties. They will still work as methods until Django 2.0, but all usage in Django now uses attribute access.

For example, if you use `AuthenticationMiddleware` and want to know whether the user is currently logged-in you would use:

    if request.user.is_authenticated:
        ... # Do something for logged-in users.
    else:
        ... # Do something for anonymous users.

instead of `request.user.is_authenticated()`.

This change avoids accidental information leakage if you forget to call the method, e.g.:

    if request.user.is_authenticated:
        return sensitive_information

If you override these methods in a custom user model, you must change them to properties or attributes.

Django uses a `CallableBool` object to allow these attributes to work as both a property and a method. Thus, until the deprecation period ends, you cannot compare these properties using the `is` operator. That is, the following won’t work:

    if request.user.is_authenticated is True:
        ...

### Custom manager classes available through `prefetch_related` must define a `_apply_rel_filters()` method

If you defined a custom manager class available through `prefetch_related()` you must make sure it defines a `_apply_rel_filters()` method.

This method must accept a `QuerySet` instance as its single argument and return a filtered version of the queryset for the model instance the manager is bound to.

### The « escape » half of `django.utils.safestring`

The `mark_for_escaping()` function and the classes it uses: `EscapeData`, `EscapeBytes`, `EscapeText`, `EscapeString`, and `EscapeUnicode` are deprecated.

As a result, the « lazy » behavior of the `escape` filter (where it would always be applied as the last filter no matter where in the filter chain it appeared) is deprecated. The filter will change to immediately apply `conditional_escape()` in Django 2.0.

### `Manager.use_for_related_fields` and inheritance changes

`Manager.use_for_related_fields` is deprecated in favor of setting `Meta.base_manager_name` on the model.

Model `Manager` inheritance will follow MRO inheritance rules in Django 2.0, changing the current behavior where managers defined on non-abstract base classes aren’t inherited by child classes. A deprecating warning with instructions on how to adapt your code is raised if you have any affected managers. You’ll either redeclare a manager from an abstract model on the child class to override the manager from the concrete model, or you’ll set the model’s `Meta.manager_inheritance_from_future=True` option to opt-in to the new inheritance behavior.

During the deprecation period, `use_for_related_fields` will be honored and raise a warning, even if a `base_manager_name` is set. This allows third-party code to preserve legacy behavior while transitioning to the new API. The warning can be silenced by setting `silence_use_for_related_fields_deprecation=True` on the manager.

### Divers

- The `makemigrations --exit` option is deprecated in favor of the `makemigrations --check` option.
- `django.utils.functional.allow_lazy()` is deprecated in favor of the new `keep_lazy()` function which can be used with a more natural decorator syntax.
- The `shell --plain` option is deprecated in favor of `-i python` or `--interface python`.
- Importing from the `django.core.urlresolvers` module is deprecated in favor of its new location, `django.urls`.
- The template `Context.has_key()` method is deprecated in favor of `in`.
- The private attribute `virtual_fields` of `Model._meta` is deprecated in favor of `private_fields`.
- The private keyword arguments `virtual_only` in `Field.contribute_to_class()` and `virtual` in `Model._meta.add_field()` are deprecated in favor of `private_only` and `private`, respectively.
- The `javascript_catalog()` and `json_catalog()` views are deprecated in favor of class-based views `JavaScriptCatalog` and `JSONCatalog`.
- In multi-table inheritance, implicit promotion of a `OneToOneField` to a `parent_link` is deprecated. Add `parent_link=True` to such fields.
- The private API `Widget._format_value()` is made public and renamed to `format_value()`. The old name will work through a deprecation period.
- Private `FileField` methods `get_directory_name()` and `get_filename()` are deprecated in favor of performing this work in `Storage.generate_filename()`).
- Old-style middleware that uses `settings.MIDDLEWARE_CLASSES` are deprecated. Adapt old, custom middleware and use the new `MIDDLEWARE` setting.

## Fonctionnalités supprimées dans 1.10

Ces fonctionnalités ont atteint la fin de leur cycle d’obsolescence et sont supprimées dans Django 1.10. Voir Features deprecated in 1.8 pour les détails, ainsi que pour savoir comment supprimer l’utilisation de ces fonctionnalités.

- Support for calling a `SQLCompiler` directly as an alias for calling its `quote_name_unless_alias` method is removed.
- The `cycle` and `firstof` template tags are removed from the `future` template tag library.
- `django.conf.urls.patterns()` is removed.
- Support for the `prefix` argument to `django.conf.urls.i18n.i18n_patterns()` is removed.
- `SimpleTestCase.urls` is removed.
- Using an incorrect count of unpacked values in the `for` template tag raises an exception rather than failing silently.
- The ability to `reverse()` URLs using a dotted Python path is removed.
- The ability to use a dotted Python path for the `LOGIN_URL` and `LOGIN_REDIRECT_URL` settings is removed.
- La prise en charge de `optparse` pour les commandes d’administration personnalisées est supprimée.
- La classe `django.core.management.NoArgsCommand` est supprimée.
- Le module `django.core.context_processors` est supprimé.
- Le module `djangodb.models.sql.aggregates` est supprimé.
- Le module `django.contrib.gis.db.models.sql.aggregates` est supprimé.
- Les méthodes et propriétés suivantes de `django.db.sql.query.Query` sont supprimées :
  - Propriétés : `aggregates` et `aggregate_select`
  - Méthodes : `add_aggregate`, `set_aggregate_mask` et `append_aggregate_mask`.
- `django.template.resolve_variable` est supprimée.
- Les API privées suivantes sont supprimées de `django.db.models.options.Options` (`Model._meta`) :
  - `get_field_by_name()`
  - `get_all_field_names()`
  - `get_fields_with_model()`
  - `get_concrete_fields_with_model()`
  - `get_m2m_with_model()`
  - `get_all_related_objects()`
  - `get_all_related_objects_with_model()`
  - `get_all_related_many_to_many_objects()`
  - `get_all_related_m2m_objects_with_model()`
- Le paramètre `error_message` de `django.forms.RegexField` est supprimé.
- The `unordered_list` filter no longer supports old style lists.
- Support for string `view` arguments to `url()` is removed.
- The backward compatible shim to rename `django.forms.Form._has_changed()` to `has_changed()` is removed.
- The `removetags` template filter is removed.
- The `remove_tags()` and `strip_entities()` functions in `django.utils.html` is removed.
- The `is_admin_site` argument to `django.contrib.auth.views.password_reset()` is removed.
- `django.db.models.field.subclassing.SubfieldBase` is removed.
- `django.utils.checksums` is removed.
- The `original_content_type_id` attribute on `django.contrib.admin.helpers.InlineAdminForm` is removed.
- The backwards compatibility shim to allow `FormMixin.get_form()` to be defined with no default value for its `form_class` argument is removed.
- The following settings are removed, and you must upgrade to the `TEMPLATES` setting:
  - `ALLOWED_INCLUDE_ROOTS`
  - `TEMPLATE_CONTEXT_PROCESSORS`
  - `TEMPLATE_DEBUG`
  - `TEMPLATE_DIRS`
  - `TEMPLATE_LOADERS`
  - `TEMPLATE_STRING_IF_INVALID`
- L’alias de rétrocompatibilité `django.template.loader.BaseLoader` est supprimé.
- Les objets de gabarit Django renvoyés par `get_template()` et `select_template()` n’acceptent plus de `Context` dans leur méthode `render()`.
- Les API de réponse de gabarit forcent l’usage de `dict` et d’objets de gabarit dépendants du moteur au lieu de respectivement `Context` et de `Template`.
- Le paramètre `current_app` a été supprimé des fonction et classes suivantes :
  - `django.shortcuts.render()`
  - `django.template.Context()`
  - `django.template.RequestContext()`
  - `django.template.response.TemplateResponse()`
- Les paramètres `dictionary` et `context_instance` ont été supprimés des fonctions suivantes :
  - `django.shortcuts.render()`
  - `django.shortcuts.render_to_response()`
  - `django.template.loader.render_to_string()`
- Le paramètre `dirs` a été supprimé des fonctions suivantes :
  - `django.template.loader.get_template()`
  - `django.template.loader.select_template()`
  - `django.shortcuts.render()`
  - `django.shortcuts.render_to_response()`
- Session verification is enabled regardless of whether or not `'django.contrib.auth.middleware.SessionAuthenticationMiddleware'` is in `MIDDLEWARE_CLASSES`. `SessionAuthenticationMiddleware` no longer has any purpose and can be removed from `MIDDLEWARE_CLASSES`. It’s kept as a stub until Django 2.0 as a courtesy for users who don’t read this note.
- L’attribut privé `django.db.models.Field.related` est supprimé.
- L’option `--list` de la commande d’administration `migrate` est supprimée.
- La balise de gabarit `ssi` est supprimée.
- La prise en charge de l’opérateur de comparaison `=` est supprimée dans la balise de gabarit `if`.
- The backwards compatibility shims to allow `Storage.get_available_name()` and `Storage.save()` to be defined without a `max_length` argument are removed.
- Support for the legacy `%(<foo>)s` syntax in `ModelFormMixin.success_url` is removed.
- `GeoQuerySet` aggregate methods `collect()`, `extent()`, `extent3d()`, `make_line()`, and `unionagg()` are removed.
- The ability to specify `ContentType.name` when creating a content type instance is removed.
- Support for the old signature of `allow_migrate` is removed.
- Support for the syntax of `{% cycle %}` that uses comma-separated arguments is removed.
- The warning that `Signer` issued when given an invalid separator is now a `ValueError`.