Notes de publication de Django 2.2

1er avril 2019

Bienvenue dans Django 2.2 !

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

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

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

Compatibilité Python

Django 2.2 supports Python 3.5, 3.6, 3.7, 3.8 (as of 2.2.8), and 3.9 (as of 2.2.17). We highly recommend and only officially support the latest release of each series.

Quoi de neuf dans Django 2.2

Contraintes

Les nouvelles classes class:~django.db.models.CheckConstraint and UniqueConstraint permettent d’ajouter des contraintes de base de données personnalisées. Ces contraintes peuvent être ajoutées aux modèles en utilisant l’option Meta.constraints.

Fonctionnalités mineures

django.contrib.admin

  • Une classe CSS a été ajoutée aux en-têtes de colonnes de TabularInline.

django.contrib.auth

django.contrib.gis

  • La prise en charge de la fonction Envelope a été ajoutée pour Oracle.
  • La prise en charge des expressions de recherche coveredby and covers a été ajoutée pour SpatiaLite.

django.contrib.postgres

  • Le nouveau paramètre ordering de ArrayAgg et StringAgg détermine l’ordre des éléments agrégés.
  • Les nouvelles classes BTreeIndex, HashIndex et SpGistIndex permettent de créer des index B-Tree, hash et SP-GiST dans la base de données.
  • BrinIndex possède maintenant le paramètre autosummarize.
  • Le nouveau paramètre search_type de SearchQuery permet de rechercher une phrase ou une expression brute.

django.contrib.staticfiles

  • La correspondance de chemins a été ajoutée à l’option collectstatic --ignore afin de pouvoir utiliser des motifs du genre /vendor/*.js.

Moteurs de base de données

Vues génériques

  • The new View.setup hook initializes view attributes before calling dispatch(). It allows mixins to set up instance attributes for reuse in child classes.

Internationalisation

  • La prise en charge des traductions en arménien a été ajoutée.

Commandes d’administration

  • La nouvelle option option:–force-color force la coloration des résultats de commandes.
  • inspectdb crée dorénavant des modèles pour les tables étrangères avec PostgreSQL.
  • inspectdb --include-views crée dorénavant des modèles pour les vues matérialisées avec Oracle et PostgreSQL.
  • La nouvelle option inspectdb --include-partitions permet de créer des modèles pour les tables de partitions avec PostgreSQL. Dans les versions précédentes, les modèles étaient créés comme tables enfants au lieu de parents.
  • inspectdb sait dorénavant découvrir les champs DurationField avec Oracle et PostgreSQL, ainsi que les champs AutoField avec SQLite.
  • Avec Oracle, dbshell est envelopéé dans rlwrap, si disponible. rlwrap fournit un historique des commandes et permet d’éditer les saisies au clavier.
  • La nouvelle option makemigrations --no-header permet d’éviter les commentaires en en-tête dans les fichiers de migration générés. Cette option est aussi disponible pour squashmigrations.
  • runserver peut dorénavant exploiter Watchman pour améliorer les performances lors de la surveillance de modification pour de nombreux fichiers.

Migrations

Modèles

  • La prise en charge des opérateurs de classes PostgreSQL (Index.opclasses) a été ajoutée.
  • La prise en charge des index partiels (Index.condition) a été ajoutée.
  • Les fonctions de base de données class:~django.db.models.functions.NullIf et Reverse ont été ajoutées, de même que de nombreuses fonctions de base de données mathématiques.
  • La définition du nouveau paramètre ignore_conflicts de QuerySet.bulk_create() à True indique à la base de données d’ignorer les insertions de lignes qui ne passent pas les contrôles d’unicité et autres contrôles.
  • La nouvelle fonction ExtractIsoYear extrait les années avec numéro de semaine ISO-8601 des champs DateField et DateTimeField, et la nouvelle expression de requête iso_year permet d’interroger selon une année avec numéro de semaine ISO-8601.
  • La nouvelle méthode QuerySet.bulk_update() permet de mettre à jour efficacement des champs spécifiques sur plusieurs instances de modèles.
  • Django ne démarre plus automatiquement une transaction lors de l’exécution d’une seule requête, telle que Model.save(), QuerySet.update() et Model.delete(). Cela améliore la performance en mode commit automatique en diminuant le nombre d’aller-retour vers la base de données.
  • La prise en charge des fonctions StdDev et Variance a été ajoutée pour SQLite.
  • La gestion des agrégats avec DISTINCT a été ajoutée à la classe Aggregate. La définition de allow_distinct = True comme attribut de classe sur des sous-classes de Aggregate permet d’indiquer un paramètre nommé distinct lors de l’initialisation pour s’assurer que la fonction d’agrégat n’est appelée que pour chaque valeur distincte de expressions.
  • Les méthodes RelatedManager.add(), create(), remove(), set(), get_or_create() et update_or_create() sont dorénavant autorisées sur des relations plusieurs-à-plusieurs avec modèle intermédiaire. Le nouveau paramètre through_defaults est utilisé pour indiquer des valeurs à définir sur la ou les instances de modèle intermédiaire.

Requêtes et réponses

  • L’attribut HttpRequest.headers a été ajouté pour permettre un accès simplifié aux en-têtes de requêtes.

Sérialisation

  • Il est dorénavant possible de désérialiser des données en utilisant des clés naturelles contenant des références en aval en passant handle_forward_references=True à serializers.deserialize(). De plus, loaddata gère automatiquement les références en aval.

Tests

  • La nouvelle assertion SimpleTestCase.assertURLEqual() vérifie l’égalité avec une URL donnée en ignorant l’ordre des paramètres de la chaîne de requête. assertRedirects() utilise cette nouvelle assertion.
  • Le client de test Client prend dorénavant en charge automatiquement la sérialisation JSON des listes et tuples data lorsque content_type='application/json'.
  • Le nouveau réglage de base de données de test ORACLE_MANAGED_FILES permet d’utiliser des espaces de tables Oracle Managed Files (OMF).
  • Les contraintes de base de données différables sont dorénavant appliquées à la fin de chaque test TestCase avec SQLite 3.20+, tout comme c’est déjà le cas pour les autres moteurs qui prennent en charge ce type de contraintes. Ces contrôles ne sont pas appliqués pour les versions plus anciennes de SQLite car ils nécessiteraient de coûteuses introspections de tables.
  • DiscoverRunner ne configure plus les bases de données qui ne sont pas référencées par les tests.

URL

Validateurs

Changements incompatibles avec les anciennes versions dans Django 2.2

API de moteur de base de données

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

  • Les moteurs de base de données de tierce-partie doivent implémenter la prise en charge des contraintes de vérification sur les tables ou définir DatabaseFeatures.supports_table_check_constraints à False.
  • Les moteurs de base de données de tierce-partie doivent implémenter la capacité d’ignorer les contraintes ou erreurs d’unicité lors d’insertions, ou définir DatabaseFeatures.supports_ignore_conflicts à False.
  • Les moteurs de base de données de tierce-partie doivent implémenter l’introspection pour DurationField ou définir DatabaseFeatures.can_introspect_duration_field à False.
  • DatabaseFeatures.uses_savepoints vaut dorénavant True par défaut.
  • Les moteurs de base de données de tierce-partie doivent implémenter la prise en charge des index partiels ou définir DatabaseFeatures.supports_partial_indexes à False.
  • DatabaseIntrospection.table_name_converter() et column_name_converter() ont été supprimées. Les moteurs de base de données de tierce-partie peuvent devoir implémenter DatabaseIntrospection.identifier_converter() à la place. Dans ce cas, les noms de contraintes renvoyés par DatabaseIntrospection.get_constraints() doivent être normalisés par identifier_converter().
  • La génération SQL des index a été déplacée de Index vers SchemaEditor et ces méthodes de SchemaEditor ont été ajoutées :
    • _create_primary_key_sql() et _delete_primary_key_sql()
    • _delete_index_sql() (en réponse à _create_index_sql())
    • _delete_unique_sql (en réponse à _create_unique_sql())
    • _delete_fk_sql() (en réponse à _create_fk_sql())
    • _create_check_sql() et _delete_check_sql()
  • Le troisième paramètre de DatabaseWrapper.__init__(), allow_thread_sharing, a été supprimé.

Les actions d’administration ne sont plus collectées à partir des classes ModelAdmin de base

Par exemple, dans les anciennes versions de Django

from django.contrib import admin


class BaseAdmin(admin.ModelAdmin):
    actions = ["a"]


class SubAdmin(BaseAdmin):
    actions = ["b"]

SubAdmin disposait des actions 'a' et 'b'.

Dorénavant les actions suivent l’héritage Python standard. Pour obtenir le même résultat qu’auparavant

class SubAdmin(BaseAdmin):
    actions = BaseAdmin.actions + ["b"]

django.contrib.gis

  • La prise en charge de GDAL 1.9 et 1.10 a été abandonnée.

Chargement de données TransactionTestCase sérialisées

Les migrations de données initiales sont dorénavant chargées dans TransactionTestCase à la fin du test, après la réinitialisation de la base de données. Dans les anciennes versions, ces données étaient chargées au début du test mais cela perturbait le fonctionnement de l’option test --keepdb (la base de données était vide à la fin de tous les tests). Cette modification ne devrait pas avoir d’impacts sur vos tests pour autant que vous n’avez pas personnalisé le fonctionnement interne de TransactionTestCase.

sqlparse devient une dépendance obligatoire

To simplify a few parts of Django’s database handling, sqlparse 0.2.2+ is now a required dependency. It’s automatically installed along with Django.

Alias de cached_property

Dans les utilisations telles que

from django.utils.functional import cached_property


class A:
    @cached_property
    def base(self):
        return ...

    alias = base

alias n’est pas mis en cache. Là où le problème peut être détecté (Python à partir de 3.6), une telle utilisation produit maintenant une exception TypeError: Cannot assign the same cached_property to two different names ('base' and 'alias').

Utilisez plutôt ceci

import operator


class A:
    ...

    alias = property(operator.attrgetter("base"))

Permissions pour les modèles mandataires

Les permissions pour les modèles mandataires sont dorénavant créées en utilisant le type de contenu du modèle mandataire plutôt que celui de leur modèle concret. Une migration va mettre à jour les permissions existantes lors de l’exécution de migrate.

Dans le site d’administration, la modification est transparente pour les modèles mandataires ayant la même étiquette app_label que leur modèle concret. Cependant, dans les anciennes versions, les utilisateurs ayant des permissions pour un modèle mandataire avec une étiquette app_label différente de celle du modèle concret n’avaient pas accès au modèle dans le site d’administration. Ceci est maintenant résolu, mais il peut valoir la peine d’auditer les attributions de permissions pour les modèles concernés ([add|view|change|delete]_monmandataire) avant la mise à jour pour être certain que les nouveaux accès soient corrects.

Pour terminer, les chaînes de permission des modèles mandataires doivent être mises à jour afin d’utiliser leur propre étiquette app_label. Par exemple, pour app.MonModeleMandataire héritant de autre_app.ModeleConcret, mettez à jour user.has_perm('autre_app.add_monmodelemandataire') en user.has_perm('app.add_monmodelemandataire').

Fusion des fichiers statiques Media des formulaires

Les fichiers statiques Media des formulaires sont dorénavant fusionnés en utilisant un algorithme de tri topologique, car l’ancien algorithme de fusion par paires était insuffisant à certains égards. Les fichiers CSS et JavaScript qui n’incluent pas leurs dépendances pourraient maintenant être triées de manière incorrecte (là où l’ancien algorithme aurait produit un résultat correct par coïncidence).

Auditer chaque classe Media à la recherche de dépendances manquantes. Par exemple, les composants dépendants de django.jQuery doivent indiquer js=['admin/js/jquery.init.js', ...] dans la déclaration des fichiers statiques de formulaires.

Divers

  • Pour améliorer la lisibilité, le champ de formulaire UUIDField affiche dorénavant les valeurs avec tirets, par exemple 550e8400-e29b-41d4-a716-446655440000 au lieu de 550e8400e29b41d4a716446655440000.

  • Avec SQLite, PositiveIntegerField et PositiveSmallIntegerField incluent dorénavant une contrainte de vérification pour éviter des valeurs négatives dans la base de données. Si des données non valides existent actuellement et que vous lancez une migration qui recrée une table, vous verrez apparaître des erreurs du type CHECK constraint failed.

  • Par cohérence avec les serveurs WSGI, le client de test définit dorénavant l’en-tête Content-Length comme chaîne au lieu de nombre entier.

  • La valeur de renvoi de django.utils.text.slugify() n’est plus marquée comme HTML sécurisé.

  • Le caractère de troncature par défaut utilisé par les filtres de gabarit urlizetrunc, truncatechars, truncatechars_html, truncatewords et truncatewords_html est désormais le caractère « points de suspension » réel () au lieu de 3 points. Il se peut que vous deviez mettre à jour certaines comparaisons dans les résultats de tests.

  • La prise en charge des chemins d’octets dans le chargeur de gabarits depuis le système de fichiers a été supprimée.

  • django.utils.http.urlsafe_base64_encode() renvoie dorénavant une chaîne au lieu d’une chaîne d’octets, et django.utils.http.urlsafe_base64_decode() n’accepte plus une chaîne d’octets en paramètre.

  • La prise en charge de cx_Oracle < 6.0 a été abandonnée.

  • La version minimum de mysqlclient prise en charge est passée de 1.3.7 à 1.3.13.

  • La version minimum de SQLite prise en charge est passée de 3.7.15 à 3.8.3.

  • Dans le but de fournir des données de requêtes un peu plus sémantiques, NullBooleanSelect produit dorénavant les valeurs d”<option> unknown, true et false au lieu de 1, 2 et 3. Par rétrocompatibilité, les données avec les anciennes valeurs sont toujours acceptées.

  • La longueur maximale max_length de Group.name a passé de 80 à 150 caractères.

  • Les tests qui violent les contraintes de base de données différables produisent dorénavant des erreurs avec SQLite 3.20+, tout comme avec les autres moteurs qui gèrent aussi ces contraintes.

  • Pour intercepter les erreurs d’utilisation, le client de test Client ainsi que django.utils.http.urlencode() génèrent maintenant une exception TypeError si None est transmis comme valeur à coder, car None ne peut pas être codé dans les données GET et POST. Transmettez plutôt une chaîne vide, ou omettez entièrement la valeur.

  • The ping_google management command now defaults to https instead of http for the sitemap’s URL. If your site uses http, use the new ping_google --sitemap-uses-http option. If you use the django.contrib.sitemaps.ping_google function, set the new sitemap_uses_https argument to False.

  • runserver no longer supports pyinotify (replaced by Watchman).

  • Les fonctions d’agrégat Avg, StdDev et Variance  renvoient dorénavant un nombre Decimal au lieu d’un float si la valeur d’entrée est un nombre Decimal.

  • Les tests échoueront avec SQLite si les applications sans migrations ont des relations à des applications avec migrations. Ceci a toujours été une limitation documentée depuis l’introduction des migrations dans Django 1.7, mais les échecs sont désormais plus constants. Vous verrez des tests échouant avec des erreurs comme no such table: <app_label>_<model>. Cela s’est produit dans plusieurs applications tierces qui ont des modèles sans migrations dans leurs tests. Vous devez ajouter des migrations pour de tel modèles.

  • Providing an integer in the key argument of the cache.delete() or cache.get() now raises ValueError.

  • Plural equations for some languages are changed, because the latest versions from Transifex are incorporated.

    Note

    The ability to handle .po files containing different plural equations for the same language was added in Django 2.2.12.

Fonctionnalités rendues obsolètes dans Django 2.2

L’attribut Meta.ordering des modèles n’affectera plus les requêtes de type GROUP BY

L’attribut Meta.ordering d’un modèle affectant les requêtes GROUP BY (telles que .annotate().values()) est une source fréquente de confusion. De telles requêtes émettent dorénavant un avertissement d’obsolescence avec le conseil d’ajouter order_by() pour conserver le comportement existant de la requête. Meta.ordering sera ignoré dans ces requêtes à partir de Django 3.1.

Divers

  • django.utils.timezone.FixedOffset a été rendu obsolète en faveur de datetime.timezone.
  • L’alias non documenté QuerySetPaginator de django.core.paginator.Paginator a été rendu obsolète.
  • Le champ de modèle et de formulaire FloatRangeField dans django.contrib.postgres a été rendu obsolète en faveur d’un nouveau nom, DecimalRangeField, pour mieux refléter le type de données numrange utilisé au niveau de la base de données.
  • Le réglage FILE_CHARSET est obsolète. À partir de Django 3.1, les fichiers lus depuis le disque doivent être codés en UTF-8.
  • django.contrib.staticfiles.storage.CachedStaticFilesStorage a été rendu obsolète en raison de ses problèmes insolubles. Remplacez-le plutôt par ManifestStaticFilesStorage ou un stockage en nuage de tierce partie.
  • RemoteUserBackend.configure_user() reçoit dorénavant request comme premier paramètre positionnel, s’il l’accepte. La prise en charge des méthodes surchargées n’acceptant pas ce paramètre sera supprimée dans Django 3.1.
  • The SimpleTestCase.allow_database_queries, TransactionTestCase.multi_db, and TestCase.multi_db attributes are deprecated in favor of SimpleTestCase.databases, TransactionTestCase.databases, and TestCase.databases. These new attributes allow databases dependencies to be declared in order to prevent unexpected queries against non-default databases to leak state between tests. The previous behavior of allow_database_queries=True and multi_db=True can be achieved by setting databases='__all__'.
Back to Top