6 avril 2021
Bienvenue dans Django 3.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 3.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 3.2 a été désigné comme une version prise en charge à long terme (LTS). Elle recevra des mises à jour de sécurité pour au moins 3 ans après sa publication initiale. La prise en charge de la version LTS précédente, Django 2.2, se terminera en avril 2022.
Django 3.2 supports Python 3.6, 3.7, 3.8, 3.9, and 3.10 (as of 3.2.9). We highly recommend and only officially support the latest release of each series.
AppConfig
¶La plupart des applications réutilisables définissent une sous-classe de AppConfig
dans un sous-module apps.py
. Elles définissent souvent une variable default_app_config
pointant vers cette classe dans leur fichier __init__.py
.
Lorsque le sous-module apps.py
existe et définit une seule sous-classe AppConfig
, Django utilise dorénavant automatiquement cette configuration, il est donc possible de supprimer default_app_config
.
default_app_config
rendait possible la déclaration simple du chemin d’application dans INSTALLED_APPS
(par ex. 'django.contrib.admin'
) au lieu du chemin complet vers la classe de configuration (par ex. 'django.contrib.admin.apps.AdminConfig'
). Cette variable avait été introduite par souci de rétrocompatibilité avec l’ancien style, dans l’intention de basculer l’écosystème dans la syntaxe plus longue, mais ceci ne s’est jamais produit.
Avec la découverte automatique des classes AppConfig
, default_app_config
n’a plus de raison d’être. Par conséquent, elle a été rendue obsolète.
Lisez Configuration des applications pour des informations plus complètes.
Lors de la définition d’un modèle, si aucun champ du modèle ne définit primary_key=True
, une clé primaire implicite est créée. Le type de cette clé primaire implicite peut dorénavant être contrôlée par le réglage DEFAULT_AUTO_FIELD
et l’attribut AppConfig.default_auto_field
. Plus besoin de surcharger les clés primaires dans tous les modèles.
Afin de conserver le comportement historique, la valeur par défaut de DEFAULT_AUTO_FIELD
est AutoField
. À partir de la version 3.2, les nouveaux projets sont générés avec DEFAULT_AUTO_FIELD
définie à BigAutoField
. De même, les nouvelles applications sont générées avec AppConfig.default_auto_field
définie à BigAutoField
. Dans une future version de Django, la valeur par défaut de DEFAULT_AUTO_FIELD
sera modifiée en BigAutoField
.
Pour éviter des migrations non souhaitées dans le futur, définissez explicitement DEFAULT_AUTO_FIELD
à AutoField
:
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
ou configurez ce réglage par application:
from django.apps import AppConfig
class MyAppConfig(AppConfig):
default_auto_field = 'django.db.models.AutoField'
name = 'my_app'
ou même encore par modèle:
from django.db import models
class MyModel(models.Model):
id = models.AutoField(primary_key=True)
Par anticipation du changement de valeur par défaut, un contrôle système produit un avertissement si vous ne définissez pas explicitement DEFAULT_AUTO_FIELD
dans votre projet.
When changing the value of DEFAULT_AUTO_FIELD
, migrations for the
primary key of existing auto-created through tables cannot be generated
currently. See the DEFAULT_AUTO_FIELD
docs for details on migrating
such tables.
Le nouveau paramètre positionnel *expressions
de Index()
permet de créer des index fonctionnels sur la base d’expressions et de fonctions de base de données. Par exemple
from django.db import models
from django.db.models import F, Index, Value
from django.db.models.functions import Lower, Upper
class MyModel(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
height = models.IntegerField()
weight = models.IntegerField()
class Meta:
indexes = [
Index(
Lower('first_name'),
Upper('last_name').desc(),
name='first_last_name_idx',
),
Index(
F('height') / (F('weight') + Value(5)),
name='calc_idx',
),
]
Les index fonctionnels peuvent être ajoutés aux modèles en utilisant l’option Meta.indexes
.
pymemcache
¶Le nouveau moteur de cache django.core.cache.backends.memcached.PyMemcacheCache
permet d’exploiter la bibliothèque pymemcache pour memcached. pymemcache
3.4.0 ou plus récent est requis. Pour plus de détails, consultez la documentation sur le cache dans Django.
Le nouveau décorateur display()
permet d’ajouter facilement des options à des fonctions d’affichage personnalisées pouvant être utilisée dans list_display
ou readonly_fields
.
De façon similaire, le nouveau décorateur action()
permet d’ajouter facilement des options à des fonctions d’action pouvant être utilisée dans actions
.
L’utilisation du décorateur @display
a l’avantage de rendre possible la syntaxe de décoration @property
lorsqu’il est nécessaire d’indiquer des attributs à une méthode personnalisée. Avant cela, il était nécessaire d’utiliser la fonction property()
après la définition des attributs nécessaires à la méthode.
L’utilisation de décorateurs a l’avantage de rendre ces options plus accessibles car elles peuvent être suggérées par des utilitaires de complétion dans des éditeurs de code. Ces décorateurs sont de simples commodités et définissent en réalité les mêmes attributs sur les fonctions, sous le capot.
django.contrib.admin
¶ModelAdmin.search_fields
autorise désormais la recherche de phrases contenant des espaces, entre guillemets.
Les champs liés en lecture seule sont maintenant affichés comme des liens navigables si les modèles cibles sont inscrits dans le site d’administration.
Le site d’administration peut maintenant être thématisé, et il contient un thème sombre activé en fonction des réglages du navigateur. Voir Prise en charge des thèmes pour plus de détails.
ModelAdmin.autocomplete_fields
respecte dorénavant attr:ForeignKey.to_field <django.db.models.ForeignKey.to_field> et ForeignKey.limit_choices_to
lors de la recherche d’un modèle lié.
Le site d’administration installe doérnavant une vue finale « attrape-tout » qui redirige les utilisateurs non authentifiés vers la page de connexion, que l’URL soit valide ou non. Ceci protège contre une potentielle faille de confidentialité par découverte de modèle.
Même si ce n’est pas recommandé, il est possible de définir le nouvel attribut AdminSite.final_catch_all_view
à False
pour désactiver cette vue « attrape-tout ».
django.contrib.auth
¶Le nombre d’itération par défaut du hacheur de mot de passe PBKDF2 a été augmenté de 216’000 à 260’000.
La variante par défaut du hacheur de mots de passe Argon2 a été changée en Argon2id. memory_cost
et parallelism
ont été respectivement augmentées à 102’400 et 8 pour correspondre aux valeurs par défaut de argon2-cffi
.
L’augmentation de la valeur memory_cost
fait augmenter la mémoire nécessaire de 512 Ko à 100 Mo. C’est toujours plutôt conservateur, mais peut amener à des problèmes de mémoire dans des environnements restreints. Dans ce genre de cas, il est possible de créer une sous-classe du hacheur existant pour surcharger les valeurs par défaut.
L’entropie par défaut du sel des hacheurs de mots de passe Argon2, MD5, PBKDF2 et SHA-1 a été augmentée de 71 à 128 bits.
django.contrib.contenttypes
¶absolute_max
de generic_inlineformset_factory()
permet de personnaliser le nombre maximum de formulaires pouvant être instanciés lors de la soumission de données POST
. Consultez Restriction du nombre maximum de formulaires instanciés pour plus de détails.can_delete_extra
de generic_inlineformset_factory()
permet de supprimer la possibilité de supprimer les formulaires supplémentaires. Voir can_delete_extra
pour plus d’informations.django.contrib.gis
¶GDALRaster.transform()
prend dorénavant en charge SpatialReference
.DataSource
prend dorénavant en charge pathlib.Path
.LayerMapping
prend dorénavant en charge pathlib.Path
.django.contrib.postgres
¶ExclusionConstraint.include
permet de créer des contraintes d’exclusion couvrantes avec PostgreSQL 12+.ExclusionConstraint.opclasses
permet de définir les classes d’opérateurs PostgreSQL.JSONBAgg.ordering
détermine l’ordre des éléments agrégés.JSONBAgg.distinct
détermine si les valeurs agrégées seront distinctes.CreateExtension
contrôle dorénavant si l’extension existe déjà dans la base de données et saute la migration le cas échéant.CreateCollation
et RemoveCollation
permettent de créer et de supprimer des collations avec PostgreSQL. Voir Gestion des collations à l’aide des migrations pour plus de détails.ArrayField
permettent dorénavant des tableaux (non imbriqués) contenant des expressions dans les parties droites des requêtes.OpClass()
permet de créer des index fonctionnels sur les expressions avec une classe d’opérateur personnalisée. Voir Index fonctionnels pour plus de détails.django.contrib.sitemaps
¶alternates
, languages
et x_default
de Sitemap
permettent de générer des versions (alternates) des plans de sites vers des versions traduites de vos pages.django.contrib.syndication
¶item_comments
permet d’indiquer une URL de commentaires par élément de flux.django_test_expected_failures
.no_append_slash()
permet à des vues individuelles d’être exclues de la normalisation des URL par APPEND_SLASH
.ExceptionReporter
peuvent maintenant définir les propriétés html_template_path
et text_template_path
pour surcharger les gabarits utilisés pour produire les rapports d’exceptions.FileUploadHandler.upload_interrupted()
permet de traiter les téléversements interrompus.absolute_max
de formset_factory()
, inlineformset_factory()
et modelformset_factory()
permet de personnaliser le nombre maximum de formulaires pouvant être instanciés lors de la soumission de données POST
. Voir Restriction du nombre maximum de formulaires instanciés pour plus de détails.can_delete_extra
de formset_factory()
, inlineformset_factory()
et modelformset_factory()
permet d’enlever la possibilité de supprimer les formulaires supplémentaires. Voir can_delete_extra
pour plus d’informations.BaseFormSet
signale dorénavant une erreur à l’utilisateur plutôt que de produire une exception. Pour personnaliser le message d’erreur, passez le paramètre error_messages
avec la clé 'missing_management_form'
lors de l’instanciation du jeu de formulaires.week_format
de class:~django.views.generic.dates.WeekMixin et WeekArchiveView
prennent désormais en charge le format de semaine ISO 8601 '%V'
.loaddata
prend désormais en charge les instantanés stockés dans des archives XZ (.xz
) et LZMA (.lzma
).dumpdata
sait désormais comprimer les données dans les formats bz2
, gz
, lzma
ou xz
.makemigrations
peut désormais être appelée sans connexion active de base de données. Dans ce cas, le contrôle de cohérence de l’historique des migrations est omis.BaseCommand.requires_system_checks
peut dorénavant accepter une liste d’étiquettes. Les contrôles système inscrits avec les étiquettes choisies seront appliqués avant d’exécuter la commande. Dans les versions précédentes, soit tous les contrôles systèmes étaient appliqués, soit aucun.Operation.migration_name_fragment
permet de fournir un fragment de nom de fichier qui sera utilisé pour nommer une migration contenant uniquement cette opération.pathlib
et os.PathLike
.no_key
de QuerySet.select_for_update()
, pris en charge par PostgreSQL, permet d’acquérir des verrous plus faibles qui ne bloquent pas la création de lignes référençant des lignes verrouillées au travers d’une clé étrangère.When()
autorise dorénavant l’utilisation du paramètre condition
avec lookups
.Index.include
et UniqueConstraint.include
permettent de créer des index couvrants et des contraintes de couverture uniques avec PostgreSQL 11+.UniqueConstraint.opclasses
permet de définir des classes d’opérateur PostgreSQL.QuerySet.update()
respecte dorénavant la clause order_by()
avec MySQL et MariaDB.FilteredRelation()
prend désormais en charge les relations imbriquées.of
de QuerySet.select_for_update()
est désormais autorisé avec MySQL 8.0.1+.Value()
résout désormais automatiquement sa valeur output_field
à la sous-classe appropriée de Field
, en fonction du type de la valeur value
fournie, pour les types bool
, bytes
, float
, int
, str
, datetime.date
, datetime.datetime
, datetime.time
, datetime.timedelta
, decimal.Decimal
et uuid.UUID
. Par conséquent, la résolution de output_field
pour les fonctions de base de données et les expressions combinatoires peuvent désormais planter avec des types mélangés lors de l’utilisation de Value()
. Dans de tels cas, il sera nécessaire de définir explicitement le type de champ output_field
.QuerySet.alias()
permet de créer des alias réutilisables pour des expressions qui n’ont pas besoin d’être sélectionnées mais qui sont utiles pour le filtrage, le tri ou comme faisant partie d’expressions complexes.Collate
permet de filtrer et de trier en respectant les collations de base de données indiquées.field_name
de QuerySet.in_bulk()
accepte dorénavant les champs distincts s’il n’existe qu’un seul champ indiqué dans QuerySet.distinct()
.tzinfo
des fonctions de base de données TruncDate
et TruncTime
permettent de tronquer les dates/heures dans un fuseau horaire déterminé.db_collation
de CharField
et:attr:TextField <django.db.models.TextField.db_collation> permet de définir une collation de base de données pour le champ.Random
a été ajoutée.F()
, OuterRef()
et d’autres expressions autorisent désormais l’utilisation de transformations. Voir Les expressions peuvent référencer des transformations pour plus de détails.durable
de atomic()
garantit que les modifications effectuées dans le bloc atomique seront validées si le bloc se termine sans erreur. Un bloc atomique imbriqué marqué comme durable produira une exception RuntimeError
.JSONObject
a été ajoutée.django.core.paginator.Paginator.get_elided_page_range()
permet de générer un intervalle de pages avec certaines valeurs éludées. Lorsqu’il y a beaucoup de pages, ceci peut s’avérer utile pour générer un nombre raisonnable de liens vers des pages dans un gabarit.HttpResponse.headers
. Ceci peut remplacer l’accès traditionnel par interface de style dictionnaire des objets HttpResponse
. Les deux interfaces continueront a être prises en charge. Voir Définition de champs d’en-tête pour plus de détails.headers
de class:~django.http.HttpResponse, SimpleTemplateResponse
et TemplateResponse
permet de définir les en-têtes de réponse headers
lors de l’instanciation.Le contenu du réglage SECRET_KEY
est dorénavant vérifié lors de son premier accès, plutôt qu’au moment du chargement des réglages. Ceci permet aux commandes d’administration qui ne dépendent pas de SECRET_KEY
de s’exécuter sans qu’une valeur soit définie. Par suite de ce changement, l’appel à configure()
sans fournir de SECRET_KEY
valable, puis poursuivre en accédant plus tard à settings.SECRET_KEY
produira une exception ImproperlyConfigured
.
Les nouvelles méthodes Signer.sign_object()
et Signer.unsign_object()
permettent de signer des structures complexes. Voir Protection de structures de données complexes pour plus de détails.
De plus, signing.dumps()
et loads()
deviennent des raccourcis de TimestampSigner.sign_object()
et unsign_object()
.
Signal.send_robust()
journalise dorénavant les exceptions.floatformat
permet dorénavant d’utiliser le suffixe g
pour forcer le groupement par THOUSAND_SEPARATOR
pour la locale active.TestCase.setUpTestData()
sont maintenant isolés pour chaque méthode de test. De tels objets doivent maintenant être capables de prendre en charge la copie profonde par copy.deepcopy()
. L’attribution d’objets qui ne prennent pas en charge deepcopy()
est obsolète et sera supprimée dans Django 4.1.DiscoverRunner
active dorénavant faulthandler
par défaut. Ceci peut être désactivé en utilisant l’option test --no-faulthandler
.DiscoverRunner
et la commande d’administration test
peut dorénavant mesurer des temps d’exécution, y compris la mise en place de la base de données et le temps total d’exécution. Ceci peut être activé en utilisant l’option test --timing
.Client
préserve dorénavant la chaîne de requête lorsqu’il suit des redirections 307 et 308.TestCase.captureOnCommitCallbacks()
capture dans une liste les fonctions de rappel transmises à transaction.on_commit()
. Cela permet de tester de telles fonctions de rappel sans devoir utiliser la classe TransactionTestCase
plus lente.TransactionTestCase.assertQuerysetEqual()
prend dorénavant en charge la comparison directe avec d’autres jeux de requête au lieu d’être limitée à la comparaison avec une liste de représentations textuelles d’objets lors de l’utilisation de la valeur par défaut de l’argument transform
.depth
des fonctions django.utils.timesince.timesince()
et django.utils.timesince.timeuntil()
permet d’indiquer le nombre d’unités de temps adjacentes à renvoyer.params
d’une erreur ValidationError
. Cela permet à des messages d’erreur personnalisés d’utiliser le substituant %(value)s
.ValidationError
ignore dorénavant l’ordre dans messages
et params
.Cette section décrit des modifications qui pourraient être nécessaires dans des moteurs de base de données tiers.
DatabaseFeatures.introspected_field_types
remplace ces capacités :can_introspect_autofield
can_introspect_big_integer_field
can_introspect_binary_field
can_introspect_decimal_field
can_introspect_duration_field
can_introspect_ip_address_field
can_introspect_positive_integer_field
can_introspect_small_integer_field
can_introspect_time_field
introspected_big_auto_field_type
introspected_small_auto_field_type
introspected_boolean_field_type
Index.include
) et les contraintes de couverture uniques (UniqueConstraint.include
), définissez DatabaseFeatures.supports_covering_indexes
à True
.CharField
et TextField
ou définir DatabaseFeatures.supports_collation_on_charfield
et DatabaseFeatures.supports_collation_on_textfield
à False
. Si les collations non déterministes ne sont pas prises en charge, définissez supports_non_deterministic_collations
à False
.DatabaseOperations.random_function_sql()
a été supprimée en faveur de la nouvelle fonction de base de données Random
.DatabaseOperations.date_trunc_sql()
et DatabaseOperations.time_trunc_sql()
acceptent dorénavant le paramètre facultatif tzname
afin de tronquer dans un fuseau horaire bien précis.DatabaseClient.runshell()
obtient dorénavant les arguments et un dictionnaire facultatif de variables d’environnement pour le client en ligne de commande sous-jacent à partir de la méthode DatabaseClient.settings_to_cmd_args_env()
. Les moteurs de bases de données tiers doivent implémenter DatabaseClient.settings_to_cmd_args_env()
ou surcharger DatabaseClient.runshell()
.Index.expressions
) ou définir DatabaseFeatures.supports_expression_indexes
à False
. Si COLLATE
ne fait pas partie de l’instruction CREATE INDEX
, définissez DatabaseFeatures.collate_as_index_expression
à True
.django.contrib.admin
¶?p=1
au lieu de ?p=0
.AdminSite.final_catch_all_view
à False
, désactivant ainsi la vue « attrape-tout ». Voir Quoi de neuf dans Django 3.2 pour plus de détails.ModelAdmin.prepopulated_fields
n’exclut plus les mots vides anglais tels que 'a'
ou 'an'
.django.contrib.gis
¶La prise en charge amont de PostgreSQL 9.5 se termine en février 2021. Django 3.2 prend en charge PostgreSQL 9.6 et plus récent.
La fin de la prise en charge amont de MySQL 5.6 est en avril 2021. Django 3.2 prend en charge MySQL 5.7 et plus récent.
Django prend dorénavant en charge les fuseaux horaires non-pytz
, tels que ceux du module zoneinfo
de Python 3.9+ et ses rétroportages.
La méthode non documentée SpatiaLiteOperations.proj4_version()
a été renommée en proj_version()
.
slugify()
supprime dorénavant les tirets et soulignements en début et fin de texte.
Les filtres de gabarit intcomma
et intword
ne dépendent plus du réglage USE_L10N
.
La prise en charge de argon2-cffi
< 19.1.0 a été abandonnée.
Les clés de cache ne contiennent plus la langue lorsque l’internationalisation est désactivée (USE_I18N = False
) et que la régionalisation est activée (USE_L10N = True
). Après la mise à jour vers Django 3.2 dans une configuration telle que celle-ci, la première requête vers une valeur précédemment en cache produira un défaut de cache.
ForeignKey.validate()
utilise dorénavant _base_manager
au lieu de _default_manager
pour vérifier si des instances liées existent.
Lorsqu’une application définit une sous-classe de AppConfig
dans un sous-module apps.py
, Django utilise désormais automatiquement cette configuration, même si elle n’est pas activée avec default_app_config
. Définisez default = False
dans la sous-classe de AppConfig
si vous voulez empêcher ce comportement. Voir Quoi de neuf dans Django 3.2 pour plus de détails.
L’instanciation d’un modèle abstrait produit dorénavant une erreur TypeError
.
Les arguments nommés de setup_databases()
sont dorénavant exclusivement des arguments nommés.
La fonction non documentée django.utils.http.limited_parse_qsl()
a été supprimée. Utilisez urllib.parse.parse_qsl()
à la place.
django.test.utils.TestContextDecorator
utilise dorénavant addCleanup()
afin que les nettoyages inscrits dans la méthode setUp()
soient appelés avant TestContextDecorator.disable()
.
SessionMiddleware
produit dorénavant l’exception exc:~django.contrib.sessions.exceptions.SessionInterrupted au lieu de SuspiciousOperation
lorsqu’une session est détruite dans une requête concurrente.
L’opérateur d’égalité de django.db.models.Field
distingue dorénavant correctement les instances de champ héritées entre modèles. De plus, l’ordre de tels champs est dorénavant défini.
La fonction non documentée django.core.files.locks.lock()
renvoie dorénavant False
si le fichier ne peut être verrouillé, au lieu de produire l’exception BlockingIOError
.
Le mécanisme de réinitialisation de mot de passe invalide dorénavant les jetons lorsque l’adresse de courriel d’un utilisateur change.
La commande makemessages
ne traite plus les locales non valables indiquées par l’option makemessages --locale
, notamment lorsqu’elles contiennent des tirets ('-'
).
Le champ de formulaire django.contrib.auth.forms.ReadOnlyPasswordHashField
est dorénavant désactivé par défaut. Par conséquent, UserChangeForm.clean_password()
n’est plus nécessaire pour renvoyer la valeur initiale.
Les opérations de cache cache.get_many()
, get_or_set()
, has_key()
, incr()
, decr()
, incr_version()
et decr_version()
gèrent maintenant correctement les valeurs None
stockées dans le cache, comme pour toute autre valeur, au lieu de faire comme si la clé n’existait pas dans le cache.
En raison d’une limitation de python-memcached
, le comportement précédent a été conservé pour le moteur obsolète MemcachedCache
.
La version minimum de SQLite prise en charge est passée de 3.8.3 à 3.9.0.
CookieStorage
stocke dorénavant ses messages dans le format compatible RFC 6265. La prise en charge des cookies utilisant l’ancien format est conservée jusqu’à Django 4.1.
La version minimum de asgiref
prise en charge est passée de 3.2.10 à 3.3.2.
copy.deepcopy()
à des attributs de classe de TestCase.setUpTestData()
est obsolète.'__all__'
au lieu de True
, et []
(une liste vide) au lieu de False
.whitelist
et l’attribut domain_whitelist
de EmailValidator
sont obsolètes. Utilisez allowlist
au lieu de whitelist
et domain_allowlist
au lieu de domain_whitelist
. Il se peut que vous deviez renommer whitelist
dans des migrations existantes.default_app_config
est osbolète, en raison de l’ajout de la découverte automatique des classes AppConfig
. Consultez Quoi de neuf dans Django 3.2 pour plus de détails.repr()
sur un jeu de requête dans TransactionTestCase.assertQuerysetEqual()
lors de la comparaison avec des chaînes est obsolète. SI vous avez besoin du comportement précédent, définissez explicitement transform
à repr
.django.core.cache.backends.memcached.MemcachedCache
est obsolète car python-memcached
présente quelques problèmes et ne semble actuellement plus maintenu. Utilisez plutôt django.core.cache.backends.memcached.PyMemcacheCache
ou django.core.cache.backends.memcached.PyLibMCCache
.django.contrib.messages.storage.cookie.CookieStorage
est différent du format généré par les anciennes versions de Django. La prise en charge de l’ancien format demeure jusqu’à Django 4.1.déc. 07, 2021