123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- ========================
- Django 4.2 release notes
- ========================
- *April 3, 2023*
- Welcome to Django 4.2!
- These release notes cover the :ref:`new features <whats-new-4.2>`, as well as
- some :ref:`backwards incompatible changes <backwards-incompatible-4.2>` you'll
- want to be aware of when upgrading from Django 4.1 or earlier. We've
- :ref:`begun the deprecation process for some features
- <deprecated-features-4.2>`.
- See the :doc:`/howto/upgrade-version` guide if you're updating an existing
- project.
- Django 4.2 is designated as a :term:`long-term support release
- <Long-term support release>`. It will receive security updates for at least
- three years after its release. Support for the previous LTS, Django 3.2, will
- end in April 2024.
- Python compatibility
- ====================
- Django 4.2 supports Python 3.8, 3.9, 3.10, 3.11, and 3.12 (as of 4.2.8). We
- **highly recommend** and only officially support the latest release of each
- series.
- .. _whats-new-4.2:
- What's new in Django 4.2
- ========================
- Psycopg 3 support
- -----------------
- Django now supports `psycopg`_ version 3.1.8 or higher. To update your code,
- install the :pypi:`psycopg library <psycopg>`, you don't need to change the
- :setting:`ENGINE <DATABASE-ENGINE>` as ``django.db.backends.postgresql``
- supports both libraries.
- Support for ``psycopg2`` is likely to be deprecated and removed at some point
- in the future.
- Be aware that ``psycopg`` 3 introduces some breaking changes over ``psycopg2``.
- As a consequence, you may need to make some changes to account for
- `differences from psycopg2`_.
- .. _psycopg: https://www.psycopg.org/psycopg3/
- .. _differences from psycopg2: https://www.psycopg.org/psycopg3/docs/basic/from_pg2.html
- Comments on columns and tables
- ------------------------------
- The new :attr:`Field.db_comment <django.db.models.Field.db_comment>` and
- :attr:`Meta.db_table_comment <django.db.models.Options.db_table_comment>`
- options allow creating comments on columns and tables, respectively. For
- example::
- from django.db import models
- class Question(models.Model):
- text = models.TextField(db_comment="Poll question")
- pub_date = models.DateTimeField(
- db_comment="Date and time when the question was published",
- )
- class Meta:
- db_table_comment = "Poll questions"
- class Answer(models.Model):
- question = models.ForeignKey(
- Question,
- on_delete=models.CASCADE,
- db_comment="Reference to a question",
- )
- answer = models.TextField(db_comment="Question answer")
- class Meta:
- db_table_comment = "Question answers"
- Also, the new :class:`~django.db.migrations.operations.AlterModelTableComment`
- operation allows changing table comments defined in the
- :attr:`Meta.db_table_comment <django.db.models.Options.db_table_comment>`.
- Mitigation for the BREACH attack
- --------------------------------
- :class:`~django.middleware.gzip.GZipMiddleware` now includes a mitigation for
- the BREACH attack. It will add up to 100 random bytes to gzip responses to make
- BREACH attacks harder. Read more about the mitigation technique in the `Heal
- The Breach (HTB) paper`_.
- .. _Heal The Breach (HTB) paper: https://ieeexplore.ieee.org/document/9754554
- In-memory file storage
- ----------------------
- The new :class:`django.core.files.storage.InMemoryStorage` class provides a
- non-persistent storage useful for speeding up tests by avoiding disk access.
- Custom file storages
- --------------------
- The new :setting:`STORAGES` setting allows configuring multiple custom file
- storage backends. It also controls storage engines for managing
- :doc:`files </topics/files>` (the ``"default"`` key) and :doc:`static files
- </ref/contrib/staticfiles>` (the ``"staticfiles"`` key).
- The old ``DEFAULT_FILE_STORAGE`` and ``STATICFILES_STORAGE`` settings are
- deprecated as of this release.
- Minor features
- --------------
- :mod:`django.contrib.admin`
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * The light or dark color theme of the admin can now be toggled in the UI, as
- well as being set to follow the system setting.
- * The admin's font stack now prefers system UI fonts and no longer requires
- downloading fonts. Additionally, CSS variables are available to more easily
- override the default font families.
- * The :source:`admin/delete_confirmation.html
- <django/contrib/admin/templates/admin/delete_confirmation.html>` template now
- has some additional blocks and scripting hooks to ease customization.
- * The chosen options of
- :attr:`~django.contrib.admin.ModelAdmin.filter_horizontal` and
- :attr:`~django.contrib.admin.ModelAdmin.filter_vertical` widgets are now
- filterable.
- * The ``admin/base.html`` template now has a new block ``nav-breadcrumbs``
- which contains the navigation landmark and the ``breadcrumbs`` block.
- * :attr:`.ModelAdmin.list_editable` now uses atomic transactions when making
- edits.
- * jQuery is upgraded from version 3.6.0 to 3.6.4.
- :mod:`django.contrib.auth`
- ~~~~~~~~~~~~~~~~~~~~~~~~~~
- * The default iteration count for the PBKDF2 password hasher is increased from
- 390,000 to 600,000.
- * :class:`~django.contrib.auth.forms.UserCreationForm` now saves many-to-many
- form fields for a custom user model.
- * The new :class:`~django.contrib.auth.forms.BaseUserCreationForm` is now the
- recommended base class for customizing the user creation form.
- :mod:`django.contrib.gis`
- ~~~~~~~~~~~~~~~~~~~~~~~~~
- * The :doc:`GeoJSON serializer </ref/contrib/gis/serializers>` now outputs the
- ``id`` key for serialized features, which defaults to the primary key of
- objects.
- * The :class:`~django.contrib.gis.gdal.GDALRaster` class now supports
- :class:`pathlib.Path`.
- * The :class:`~django.contrib.gis.geoip2.GeoIP2` class now supports ``.mmdb``
- files downloaded from DB-IP.
- * The OpenLayers template widget no longer includes inline CSS (which also
- removes the former ``map_css`` block) to better comply with a strict Content
- Security Policy.
- * :class:`~django.contrib.gis.forms.widgets.OpenLayersWidget` is now based on
- OpenLayers 7.2.2 (previously 4.6.5).
- * The new :lookup:`isempty` lookup and
- :class:`IsEmpty() <django.contrib.gis.db.models.functions.IsEmpty>`
- expression allow filtering empty geometries on PostGIS.
- * The new :class:`FromWKB() <django.contrib.gis.db.models.functions.FromWKB>`
- and :class:`FromWKT() <django.contrib.gis.db.models.functions.FromWKT>`
- functions allow creating geometries from Well-known binary (WKB) and
- Well-known text (WKT) representations.
- :mod:`django.contrib.postgres`
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * The new :lookup:`trigram_strict_word_similar` lookup, and the
- :class:`TrigramStrictWordSimilarity()
- <django.contrib.postgres.search.TrigramStrictWordSimilarity>` and
- :class:`TrigramStrictWordDistance()
- <django.contrib.postgres.search.TrigramStrictWordDistance>` expressions allow
- using trigram strict word similarity.
- * The :lookup:`arrayfield.overlap` lookup now supports ``QuerySet.values()``
- and ``values_list()`` as a right-hand side.
- :mod:`django.contrib.sitemaps`
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * The new :meth:`.Sitemap.get_languages_for_item` method allows customizing the
- list of languages for which the item is displayed.
- :mod:`django.contrib.staticfiles`
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` now
- has experimental support for replacing paths to JavaScript modules in
- ``import`` and ``export`` statements with their hashed counterparts. If you
- want to try it, subclass ``ManifestStaticFilesStorage`` and set the
- ``support_js_module_import_aggregation`` attribute to ``True``.
- * The new :attr:`.ManifestStaticFilesStorage.manifest_hash` attribute provides
- a hash over all files in the manifest and changes whenever one of the files
- changes.
- Database backends
- ~~~~~~~~~~~~~~~~~
- * The new ``"assume_role"`` option is now supported in :setting:`OPTIONS` on
- PostgreSQL to allow specifying the :ref:`session role <database-role>`.
- * The new ``"server_side_binding"`` option is now supported in
- :setting:`OPTIONS` on PostgreSQL with ``psycopg`` 3.1.8+ to allow using
- :ref:`server-side binding cursors <database-server-side-parameters-binding>`.
- Error Reporting
- ~~~~~~~~~~~~~~~
- * The debug page now shows :pep:`exception notes <678>` and
- :pep:`fine-grained error locations <657>` on Python 3.11+.
- * Session cookies are now treated as credentials and therefore hidden and
- replaced with stars (``**********``) in error reports.
- Forms
- ~~~~~
- * :class:`~django.forms.ModelForm` now accepts the new ``Meta`` option
- ``formfield_callback`` to customize form fields.
- * :func:`~django.forms.models.modelform_factory` now respects the
- ``formfield_callback`` attribute of the ``form``’s ``Meta``.
- Internationalization
- ~~~~~~~~~~~~~~~~~~~~
- * Added support and translations for the Central Kurdish (Sorani) language.
- Logging
- ~~~~~~~
- * The :ref:`django-db-logger` logger now logs transaction management queries
- (``BEGIN``, ``COMMIT``, and ``ROLLBACK``) at the ``DEBUG`` level.
- Management Commands
- ~~~~~~~~~~~~~~~~~~~
- * :djadmin:`makemessages` command now supports locales with private sub-tags
- such as ``nl_NL-x-informal``.
- * The new :option:`makemigrations --update` option merges model changes into
- the latest migration and optimizes the resulting operations.
- Migrations
- ~~~~~~~~~~
- * Migrations now support serialization of ``enum.Flag`` objects.
- Models
- ~~~~~~
- * ``QuerySet`` now extensively supports filtering against
- :ref:`window-functions` with the exception of disjunctive filter lookups
- against window functions when performing aggregation.
- * :meth:`~.QuerySet.prefetch_related` now supports
- :class:`~django.db.models.Prefetch` objects with sliced querysets.
- * :ref:`Registering lookups <lookup-registration-api>` on
- :class:`~django.db.models.Field` instances is now supported.
- * The new ``robust`` argument for :func:`~django.db.transaction.on_commit`
- allows performing actions that can fail after a database transaction is
- successfully committed.
- * The new :class:`KT() <django.db.models.fields.json.KT>` expression represents
- the text value of a key, index, or path transform of
- :class:`~django.db.models.JSONField`.
- * :class:`~django.db.models.functions.Now` now supports microsecond precision
- on MySQL and millisecond precision on SQLite.
- * :class:`F() <django.db.models.F>` expressions that output ``BooleanField``
- can now be negated using ``~F()`` (inversion operator).
- * ``Model`` now provides asynchronous versions of some methods that use the
- database, using an ``a`` prefix: :meth:`~.Model.adelete`,
- :meth:`~.Model.arefresh_from_db`, and :meth:`~.Model.asave`.
- * Related managers now provide asynchronous versions of methods that change a
- set of related objects, using an ``a`` prefix: :meth:`~.RelatedManager.aadd`,
- :meth:`~.RelatedManager.aclear`, :meth:`~.RelatedManager.aremove`, and
- :meth:`~.RelatedManager.aset`.
- * :attr:`CharField.max_length <django.db.models.CharField.max_length>` is no
- longer required to be set on PostgreSQL, which supports unlimited ``VARCHAR``
- columns.
- Requests and Responses
- ~~~~~~~~~~~~~~~~~~~~~~
- * :class:`~django.http.StreamingHttpResponse` now supports async iterators
- when Django is served via ASGI.
- Tests
- ~~~~~
- * The :option:`test --debug-sql` option now formats SQL queries with
- ``sqlparse``.
- * The :class:`~django.test.RequestFactory`,
- :class:`~django.test.AsyncRequestFactory`, :class:`~django.test.Client`, and
- :class:`~django.test.AsyncClient` classes now support the ``headers``
- parameter, which accepts a dictionary of header names and values. This allows
- a more natural syntax for declaring headers.
- .. code-block:: python
- # Before:
- self.client.get("/home/", HTTP_ACCEPT_LANGUAGE="fr")
- await self.async_client.get("/home/", ACCEPT_LANGUAGE="fr")
- # After:
- self.client.get("/home/", headers={"accept-language": "fr"})
- await self.async_client.get("/home/", headers={"accept-language": "fr"})
- Utilities
- ~~~~~~~~~
- * The new ``encoder`` parameter for :meth:`django.utils.html.json_script`
- function allows customizing a JSON encoder class.
- * The private internal vendored copy of ``urllib.parse.urlsplit()`` now strips
- ``'\r'``, ``'\n'``, and ``'\t'`` (see :cve:`2022-0391` and :bpo:`43882`).
- This is to protect projects that may be incorrectly using the internal
- ``url_has_allowed_host_and_scheme()`` function, instead of using one of the
- documented functions for handling URL redirects. The Django functions were
- not affected.
- * The new :func:`django.utils.http.content_disposition_header` function returns
- a ``Content-Disposition`` HTTP header value as specified by :rfc:`6266`.
- Validators
- ~~~~~~~~~~
- * The list of common passwords used by ``CommonPasswordValidator`` is updated
- to the most recent version.
- .. _backwards-incompatible-4.2:
- Backwards incompatible changes in 4.2
- =====================================
- Database backend API
- --------------------
- This section describes changes that may be needed in third-party database
- backends.
- * ``DatabaseFeatures.allows_group_by_pk`` is removed as it only remained to
- accommodate a MySQL extension that has been supplanted by proper functional
- dependency detection in MySQL 5.7.15. Note that
- ``DatabaseFeatures.allows_group_by_selected_pks`` is still supported and
- should be enabled if your backend supports functional dependency detection in
- ``GROUP BY`` clauses as specified by the ``SQL:1999`` standard.
- * :djadmin:`inspectdb` now uses ``display_size`` from
- ``DatabaseIntrospection.get_table_description()`` rather than
- ``internal_size`` for ``CharField``.
- Dropped support for MariaDB 10.3
- --------------------------------
- Upstream support for MariaDB 10.3 ends in May 2023. Django 4.2 supports MariaDB
- 10.4 and higher.
- Dropped support for MySQL 5.7
- -----------------------------
- Upstream support for MySQL 5.7 ends in October 2023. Django 4.2 supports MySQL
- 8 and higher.
- Dropped support for PostgreSQL 11
- ---------------------------------
- Upstream support for PostgreSQL 11 ends in November 2023. Django 4.2 supports
- PostgreSQL 12 and higher.
- Setting ``update_fields`` in ``Model.save()`` may now be required
- -----------------------------------------------------------------
- In order to avoid updating unnecessary columns,
- :meth:`.QuerySet.update_or_create` now passes ``update_fields`` to the
- :meth:`Model.save() <django.db.models.Model.save>` calls. As a consequence, any
- fields modified in the custom ``save()`` methods should be added to the
- ``update_fields`` keyword argument before calling ``super()``. See
- :ref:`overriding-model-methods` for more details.
- Miscellaneous
- -------------
- * The undocumented ``django.http.multipartparser.parse_header()`` function is
- removed. Use ``django.utils.http.parse_header_parameters()`` instead.
- * :ttag:`{% blocktranslate asvar … %}<blocktranslate>` result is now marked as
- safe for (HTML) output purposes.
- * The ``autofocus`` HTML attribute in the admin search box is removed as it can
- be confusing for screen readers.
- * The :option:`makemigrations --check` option no longer creates missing
- migration files.
- * The ``alias`` argument for :meth:`.Expression.get_group_by_cols` is removed.
- * The minimum supported version of ``sqlparse`` is increased from 0.2.2 to
- 0.3.1.
- * The undocumented ``negated`` parameter of the
- :class:`~django.db.models.Exists` expression is removed.
- * The ``is_summary`` argument of the undocumented ``Query.add_annotation()``
- method is removed.
- * The minimum supported version of SQLite is increased from 3.9.0 to 3.21.0.
- * The minimum supported version of ``asgiref`` is increased from 3.5.2 to
- 3.6.0.
- * :class:`~django.contrib.auth.forms.UserCreationForm` now rejects usernames
- that differ only in case. If you need the previous behavior, use
- :class:`~django.contrib.auth.forms.BaseUserCreationForm` instead.
- * The minimum supported version of ``mysqlclient`` is increased from 1.4.0 to
- 1.4.3.
- * The minimum supported version of ``argon2-cffi`` is increased from 19.1.0 to
- 19.2.0.
- * The minimum supported version of ``Pillow`` is increased from 6.2.0 to 6.2.1.
- * The minimum supported version of ``jinja2`` is increased from 2.9.2 to
- 2.11.0.
- * The minimum supported version of :pypi:`redis-py <redis>` is increased from
- 3.0.0 to 3.4.0.
- * Manually instantiated ``WSGIRequest`` objects must be provided a file-like
- object for ``wsgi.input``. Previously, Django was more lax than the expected
- behavior as specified by the WSGI specification.
- * Support for ``PROJ`` < 5 is removed.
- * :class:`~django.core.mail.backends.smtp.EmailBackend` now verifies a
- :py:attr:`hostname <ssl.SSLContext.check_hostname>` and
- :py:attr:`certificates <ssl.SSLContext.verify_mode>`. If you need the
- previous behavior that is less restrictive and not recommended, subclass
- ``EmailBackend`` and override the ``ssl_context`` property.
- .. _deprecated-features-4.2:
- Features deprecated in 4.2
- ==========================
- ``index_together`` option is deprecated in favor of ``indexes``
- ---------------------------------------------------------------
- The :attr:`Meta.index_together <django.db.models.Options.index_together>`
- option is deprecated in favor of the :attr:`~django.db.models.Options.indexes`
- option.
- Migrating existing ``index_together`` should be handled as a migration. For
- example::
- class Author(models.Model):
- rank = models.IntegerField()
- name = models.CharField(max_length=30)
- class Meta:
- index_together = [["rank", "name"]]
- Should become::
- class Author(models.Model):
- rank = models.IntegerField()
- name = models.CharField(max_length=30)
- class Meta:
- indexes = [models.Index(fields=["rank", "name"])]
- Running the :djadmin:`makemigrations` command will generate a migration
- containing a :class:`~django.db.migrations.operations.RenameIndex` operation
- which will rename the existing index. Next, consider squashing migrations to
- remove ``index_together`` from historical migrations.
- The ``AlterIndexTogether`` migration operation is now officially supported only
- for pre-Django 4.2 migration files. For backward compatibility reasons, it's
- still part of the public API, and there's no plan to deprecate or remove it,
- but it should not be used for new migrations. Use
- :class:`~django.db.migrations.operations.AddIndex` and
- :class:`~django.db.migrations.operations.RemoveIndex` operations instead.
- Passing encoded JSON string literals to ``JSONField`` is deprecated
- -------------------------------------------------------------------
- ``JSONField`` and its associated lookups and aggregates used to allow passing
- JSON encoded string literals which caused ambiguity on whether string literals
- were already encoded from database backend's perspective.
- During the deprecation period string literals will be attempted to be JSON
- decoded and a warning will be emitted on success that points at passing
- non-encoded forms instead.
- Code that used to pass JSON encoded string literals::
- Document.objects.bulk_create(
- Document(data=Value("null")),
- Document(data=Value("[]")),
- Document(data=Value('"foo-bar"')),
- )
- Document.objects.annotate(
- JSONBAgg("field", default=Value("[]")),
- )
- Should become::
- Document.objects.bulk_create(
- Document(data=Value(None, JSONField())),
- Document(data=[]),
- Document(data="foo-bar"),
- )
- Document.objects.annotate(
- JSONBAgg("field", default=[]),
- )
- From Django 5.1+ string literals will be implicitly interpreted as JSON string
- literals.
- Miscellaneous
- -------------
- * The ``BaseUserManager.make_random_password()`` method is deprecated. See
- `recipes and best practices
- <https://docs.python.org/3/library/secrets.html#recipes-and-best-practices>`_
- for using Python's :py:mod:`secrets` module to generate passwords.
- * The ``length_is`` template filter is deprecated in favor of :tfilter:`length`
- and the ``==`` operator within an :ttag:`{% if %}<if>` tag. For example
- .. code-block:: html+django
- {% if value|length == 4 %}…{% endif %}
- {% if value|length == 4 %}True{% else %}False{% endif %}
- instead of:
- .. code-block:: html+django
- {% if value|length_is:4 %}…{% endif %}
- {{ value|length_is:4 }}
- * ``django.contrib.auth.hashers.SHA1PasswordHasher``,
- ``django.contrib.auth.hashers.UnsaltedSHA1PasswordHasher``, and
- ``django.contrib.auth.hashers.UnsaltedMD5PasswordHasher`` are deprecated.
- * ``django.contrib.postgres.fields.CICharField`` is deprecated in favor of
- ``CharField(db_collation="…")`` with a case-insensitive non-deterministic
- collation.
- * ``django.contrib.postgres.fields.CIEmailField`` is deprecated in favor of
- ``EmailField(db_collation="…")`` with a case-insensitive non-deterministic
- collation.
- * ``django.contrib.postgres.fields.CITextField`` is deprecated in favor of
- ``TextField(db_collation="…")`` with a case-insensitive non-deterministic
- collation.
- * ``django.contrib.postgres.fields.CIText`` mixin is deprecated.
- * The ``map_height`` and ``map_width`` attributes of ``BaseGeometryWidget`` are
- deprecated, use CSS to size map widgets instead.
- * ``SimpleTestCase.assertFormsetError()`` is deprecated in favor of
- ``assertFormSetError()``.
- * ``TransactionTestCase.assertQuerysetEqual()`` is deprecated in favor of
- ``assertQuerySetEqual()``.
- * Passing positional arguments to ``Signer`` and ``TimestampSigner`` is
- deprecated in favor of keyword-only arguments.
- * The ``DEFAULT_FILE_STORAGE`` setting is deprecated in favor of
- ``STORAGES["default"]``.
- * The ``STATICFILES_STORAGE`` setting is deprecated in favor of
- ``STORAGES["staticfiles"]``.
- * The ``django.core.files.storage.get_storage_class()`` function is deprecated.
|