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

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

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.

_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:

LOGGING = {
    # ...
    "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:

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 ManyToManyFields.
  • 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 datetimes 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).

__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:
    ...

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.

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.
Back to Top