======================== Django 4.1 release notes ======================== *August 3, 2022* Welcome to Django 4.1! These release notes cover the :ref:`new features `, as well as some :ref:`backwards incompatible changes ` you'll want to be aware of when upgrading from Django 4.0 or earlier. We've :ref:`begun the deprecation process for some features `. See the :doc:`/howto/upgrade-version` guide if you're updating an existing project. Python compatibility ==================== Django 4.1 supports Python 3.8, 3.9, 3.10, and 3.11 (as of 4.1.3). We **highly recommend** and only officially support the latest release of each series. .. _whats-new-4.1: What's new in Django 4.1 ======================== Asynchronous handlers for class-based views ------------------------------------------- View subclasses may now define async HTTP method handlers:: import asyncio from django.http import HttpResponse from django.views import View class AsyncView(View): async def get(self, request, *args, **kwargs): # Perform view logic using await. await asyncio.sleep(1) return HttpResponse("Hello async world!") See :ref:`async-class-based-views` for more details. Asynchronous ORM interface -------------------------- ``QuerySet`` now provides an asynchronous interface for all data access operations. These are named as-per the existing synchronous operations but with an ``a`` prefix, for example ``acreate()``, ``aget()``, and so on. The new interface allows you to write asynchronous code without needing to wrap ORM operations in ``sync_to_async()``:: async for author in Author.objects.filter(name__startswith="A"): book = await author.books.afirst() Note that, at this stage, the underlying database operations remain synchronous, with contributions ongoing to push asynchronous support down into the SQL compiler, and integrate asynchronous database drivers. The new asynchronous queryset interface currently encapsulates the necessary ``sync_to_async()`` operations for you, and will allow your code to take advantage of developments in the ORM's asynchronous support as it evolves. See :ref:`async-queries` for details and limitations. Validation of Constraints ------------------------- :class:`Check `, :class:`unique `, and :class:`exclusion ` constraints defined in the :attr:`Meta.constraints ` option are now checked during :ref:`model validation `. Form rendering accessibility ---------------------------- In order to aid users with screen readers, and other assistive technology, new ``
`` based form templates are available from this release. These provide more accessible navigation than the older templates, and are able to correctly group related controls, such as radio-lists, into fieldsets. The new templates are recommended, and will become the default form rendering style when outputting a form, like ``{{ form }}`` in a template, from Django 5.0. In order to ease adopting the new output style, the default form and formset templates are now configurable at the project level via the :setting:`FORM_RENDERER` setting. See :ref:`the Forms section (below)` for full details. .. _csrf-cookie-masked-usage: ``CSRF_COOKIE_MASKED`` setting ------------------------------ The new ``CSRF_COOKIE_MASKED`` transitional setting allows specifying whether to mask the CSRF cookie. :class:`~django.middleware.csrf.CsrfViewMiddleware` no longer masks the CSRF cookie like it does the CSRF token in the DOM. If you are upgrading multiple instances of the same project to Django 4.1, you should set ``CSRF_COOKIE_MASKED`` to ``True`` during the transition, in order to allow compatibility with the older versions of Django. Once the transition to 4.1 is complete you can stop overriding ``CSRF_COOKIE_MASKED``. This setting is deprecated as of this release and will be removed in Django 5.0. Minor features -------------- :mod:`django.contrib.admin` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ * The admin :ref:`dark mode CSS variables ` are now applied in a separate stylesheet and template block. * :ref:`modeladmin-list-filters` providing custom ``FieldListFilter`` subclasses can now control the query string value separator when filtering for multiple values using the ``__in`` lookup. * The admin :meth:`history view ` is now paginated. * Related widget wrappers now have a link to object's change form. * The :meth:`.AdminSite.get_app_list` method now allows changing the order of apps and models on the admin index page. :mod:`django.contrib.auth` ~~~~~~~~~~~~~~~~~~~~~~~~~~ * The default iteration count for the PBKDF2 password hasher is increased from 320,000 to 390,000. * The :meth:`.RemoteUserBackend.configure_user` method now allows synchronizing user attributes with attributes in a remote system such as an LDAP directory. :mod:`django.contrib.gis` ~~~~~~~~~~~~~~~~~~~~~~~~~ * The new :meth:`.GEOSGeometry.make_valid()` method allows converting invalid geometries to valid ones. * The new ``clone`` argument for :meth:`.GEOSGeometry.normalize` allows creating a normalized clone of the geometry. :mod:`django.contrib.postgres` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * The new :class:`BitXor() ` aggregate function returns an ``int`` of the bitwise ``XOR`` of all non-null input values. * :class:`~django.contrib.postgres.indexes.SpGistIndex` now supports covering indexes on PostgreSQL 14+. * :class:`~django.contrib.postgres.constraints.ExclusionConstraint` now supports covering exclusion constraints using SP-GiST indexes on PostgreSQL 14+. * The new ``default_bounds`` attribute of :attr:`DateTimeRangeField ` and :attr:`DecimalRangeField ` allows specifying bounds for list and tuple inputs. * :class:`~django.contrib.postgres.constraints.ExclusionConstraint` now allows specifying operator classes with the :class:`OpClass() ` expression. :mod:`django.contrib.sitemaps` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * The default sitemap index template ```` now includes the ```` timestamp where available, through the new :meth:`~django.contrib.sitemaps.Sitemap.get_latest_lastmod` method. Custom sitemap index templates should be updated for the adjusted :ref:`context variables `. :mod:`django.contrib.staticfiles` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` now replaces paths to CSS source map references with their hashed counterparts. Database backends ~~~~~~~~~~~~~~~~~ * Third-party database backends can now specify the minimum required version of the database using the ``DatabaseFeatures.minimum_database_version`` attribute which is a tuple (e.g. ``(10, 0)`` means "10.0"). If a minimum version is specified, backends must also implement ``DatabaseWrapper.get_database_version()``, which returns a tuple of the current database version. The backend's ``DatabaseWrapper.init_connection_state()`` method must call ``super()`` in order for the check to run. .. _forms-4.1: Forms ~~~~~ * The default template used to render forms when cast to a string, e.g. in templates as ``{{ form }}``, is now configurable at the project-level by setting :attr:`~django.forms.renderers.BaseRenderer.form_template_name` on the class provided for :setting:`FORM_RENDERER`. :attr:`.Form.template_name` is now a property deferring to the renderer, but may be overridden with a string value to specify the template name per-form class. Similarly, the default template used to render formsets can be specified via the matching :attr:`~django.forms.renderers.BaseRenderer.formset_template_name` renderer attribute. * The new ``div.html`` form template, referencing :attr:`.Form.template_name_div` attribute, and matching :meth:`.Form.as_div` method, render forms using HTML ``
`` elements. This new output style is recommended over the existing :meth:`~.Form.as_table`, :meth:`~.Form.as_p` and :meth:`~.Form.as_ul` styles, as the template implements ``
`` and ```` to group related inputs and is easier for screen reader users to navigate. The div-based output will become the default rendering style from Django 5.0. * In order to smooth adoption of the new ``
`` output style, two transitional form renderer classes are available: ``django.forms.renderers.DjangoDivFormRenderer`` and ``django.forms.renderers.Jinja2DivFormRenderer``, for the Django and Jinja2 template backends respectively. You can apply one of these via the :setting:`FORM_RENDERER` setting. For example:: FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer" Once the ``
`` output style is the default, from Django 5.0, these transitional renderers will be deprecated, for removal in Django 6.0. The ``FORM_RENDERER`` declaration can be removed at that time. * If the new ``
`` output style is not appropriate for your project, you should define a renderer subclass specifying :attr:`~django.forms.renderers.BaseRenderer.form_template_name` and :attr:`~django.forms.renderers.BaseRenderer.formset_template_name` for your required style, and set :setting:`FORM_RENDERER` accordingly. For example, for the ``

`` output style used by :meth:`~.Form.as_p`, you would define a form renderer setting ``form_template_name`` to ``"django/forms/p.html"`` and ``formset_template_name`` to ``"django/forms/formsets/p.html"``. * The new :meth:`~django.forms.BoundField.legend_tag` allows rendering field labels in ```` tags via the new ``tag`` argument of :meth:`~django.forms.BoundField.label_tag`. * The new ``edit_only`` argument for :func:`.modelformset_factory` and :func:`.inlineformset_factory` allows preventing new objects creation. * The ``js`` and ``css`` class attributes of :doc:`Media ` now allow using hashable objects, not only path strings, as long as those objects implement the ``__html__()`` method (typically when decorated with the :func:`~django.utils.html.html_safe` decorator). * The new :attr:`.BoundField.use_fieldset` and :attr:`.Widget.use_fieldset` attributes help to identify widgets where its inputs should be grouped in a ``

`` with a ````. * The :ref:`formsets-error-messages` argument for :class:`~django.forms.formsets.BaseFormSet` now allows customizing error messages for invalid number of forms by passing ``'too_few_forms'`` and ``'too_many_forms'`` keys. * :class:`~django.forms.IntegerField`, :class:`~django.forms.FloatField`, and :class:`~django.forms.DecimalField` now optionally accept a ``step_size`` argument. This is used to set the ``step`` HTML attribute, and is validated on form submission. Internationalization ~~~~~~~~~~~~~~~~~~~~ * The :func:`~django.conf.urls.i18n.i18n_patterns` function now supports languages with both scripts and regions. Management Commands ~~~~~~~~~~~~~~~~~~~ * :option:`makemigrations --no-input` now logs default answers and reasons why migrations cannot be created. * The new :option:`makemigrations --scriptable` option diverts log output and input prompts to ``stderr``, writing only paths of generated migration files to ``stdout``. * The new :option:`migrate --prune` option allows deleting nonexistent migrations from the ``django_migrations`` table. * Python files created by :djadmin:`startproject`, :djadmin:`startapp`, :djadmin:`optimizemigration`, :djadmin:`makemigrations`, and :djadmin:`squashmigrations` are now formatted using the ``black`` command if it is present on your ``PATH``. * The new :djadmin:`optimizemigration` command allows optimizing operations for a migration. Migrations ~~~~~~~~~~ * The new :class:`~django.db.migrations.operations.RenameIndex` operation allows renaming indexes defined in the :attr:`Meta.indexes ` or ``index_together`` options. * The migrations autodetector now generates :class:`~django.db.migrations.operations.RenameIndex` operations instead of ``RemoveIndex`` and ``AddIndex``, when renaming indexes defined in the :attr:`Meta.indexes `. * The migrations autodetector now generates :class:`~django.db.migrations.operations.RenameIndex` operations instead of ``AlterIndexTogether`` and ``AddIndex``, when moving indexes defined in the ``Meta.index_together`` to the :attr:`Meta.indexes `. Models ~~~~~~ * The ``order_by`` argument of the :class:`~django.db.models.expressions.Window` expression now accepts string references to fields and transforms. * The new :setting:`CONN_HEALTH_CHECKS` setting allows enabling health checks for :ref:`persistent database connections ` in order to reduce the number of failed requests, e.g. after database server restart. * :meth:`.QuerySet.bulk_create` now supports updating fields when a row insertion fails uniqueness constraints. This is supported on MariaDB, MySQL, PostgreSQL, and SQLite 3.24+. * :meth:`.QuerySet.iterator` now supports prefetching related objects as long as the ``chunk_size`` argument is provided. In older versions, no prefetching was done. * :class:`~django.db.models.Q` objects and querysets can now be combined using ``^`` as the exclusive or (``XOR``) operator. ``XOR`` is natively supported on MariaDB and MySQL. For databases that do not support ``XOR``, the query will be converted to an equivalent using ``AND``, ``OR``, and ``NOT``. * The new :ref:`Field.non_db_attrs ` attribute allows customizing attributes of fields that don't affect a column definition. * On PostgreSQL, ``AutoField``, ``BigAutoField``, and ``SmallAutoField`` are now created as identity columns rather than serial columns with sequences. Requests and Responses ~~~~~~~~~~~~~~~~~~~~~~ * :meth:`.HttpResponse.set_cookie` now supports :class:`~datetime.timedelta` objects for the ``max_age`` argument. Security ~~~~~~~~ * The new :setting:`SECRET_KEY_FALLBACKS` setting allows providing a list of values for secret key rotation. * The :setting:`SECURE_PROXY_SSL_HEADER` setting now supports a comma-separated list of protocols in the header value. Signals ~~~~~~~ * The :data:`~django.db.models.signals.pre_delete` and :data:`~django.db.models.signals.post_delete` signals now dispatch the ``origin`` of the deletion. .. _templates-4.1: Templates ~~~~~~~~~ * The HTML ``