2021-01-05 18:07:46 +08:00
|
|
|
============================================
|
|
|
|
Django 4.0 release notes - UNDER DEVELOPMENT
|
|
|
|
============================================
|
|
|
|
|
|
|
|
*Expected December 2021*
|
|
|
|
|
|
|
|
Welcome to Django 4.0!
|
|
|
|
|
|
|
|
These release notes cover the :ref:`new features <whats-new-4.0>`, as well as
|
|
|
|
some :ref:`backwards incompatible changes <backwards-incompatible-4.0>` you'll
|
|
|
|
want to be aware of when upgrading from Django 3.2 or earlier. We've
|
|
|
|
:ref:`begun the deprecation process for some features
|
|
|
|
<deprecated-features-4.0>`.
|
|
|
|
|
|
|
|
See the :doc:`/howto/upgrade-version` guide if you're updating an existing
|
|
|
|
project.
|
|
|
|
|
|
|
|
Python compatibility
|
|
|
|
====================
|
|
|
|
|
|
|
|
Django 4.0 supports Python 3.8, 3.9, and 3.10. We **highly recommend** and only
|
|
|
|
officially support the latest release of each series.
|
|
|
|
|
2021-01-19 15:35:16 +08:00
|
|
|
The Django 3.2.x series is the last to support Python 3.6 and 3.7.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
.. _whats-new-4.0:
|
|
|
|
|
|
|
|
What's new in Django 4.0
|
|
|
|
========================
|
|
|
|
|
2021-09-09 21:15:44 +08:00
|
|
|
``zoneinfo`` default timezone implementation
|
|
|
|
--------------------------------------------
|
|
|
|
|
|
|
|
The Python standard library's :mod:`zoneinfo` is now the default timezone
|
|
|
|
implementation in Django.
|
|
|
|
|
|
|
|
This is the next step in the migration from using ``pytz`` to using
|
|
|
|
:mod:`zoneinfo`. Django 3.2 allowed the use of non-``pytz`` time zones. Django
|
|
|
|
4.0 makes ``zoneinfo`` the default implementation. Support for ``pytz`` is now
|
|
|
|
deprecated and will be removed in Django 5.0.
|
|
|
|
|
|
|
|
:mod:`zoneinfo` is part of the Python standard library from Python 3.9. The
|
|
|
|
``backports.zoneinfo`` package is automatically installed alongside Django if
|
|
|
|
you are using Python 3.8.
|
|
|
|
|
|
|
|
The move to ``zoneinfo`` should be largely transparent. Selection of the
|
|
|
|
current timezone, conversion of datetime instances to the current timezone in
|
|
|
|
forms and templates, as well as operations on aware datetimes in UTC are
|
|
|
|
unaffected.
|
|
|
|
|
|
|
|
However, if you are you are working with non-UTC time zones, and using the
|
|
|
|
``pytz`` ``normalize()`` and ``localize()`` APIs, possibly with the
|
|
|
|
:setting:`DATABASE-TIME_ZONE` setting, you will need to audit your code, since
|
|
|
|
``pytz`` and ``zoneinfo`` are not entirely equivalent.
|
|
|
|
|
|
|
|
To give time for such an audit, the transitional :setting:`USE_DEPRECATED_PYTZ`
|
|
|
|
setting allows continued use of ``pytz`` during the 4.x release cycle. This
|
|
|
|
setting will be removed in Django 5.0.
|
|
|
|
|
|
|
|
In addition, a `pytz_deprecation_shim`_ package, created by the ``zoneinfo``
|
|
|
|
author, can be used to assist with the migration from ``pytz``. This package
|
|
|
|
provides shims to help you safely remove ``pytz``, and has a detailed
|
|
|
|
`migration guide`_ showing how to move to the new ``zoneinfo`` APIs.
|
|
|
|
|
|
|
|
Using `pytz_deprecation_shim`_ and the :setting:`USE_DEPRECATED_PYTZ`
|
|
|
|
transitional setting is recommended if you need a gradual update path.
|
|
|
|
|
|
|
|
.. _pytz_deprecation_shim: https://pytz-deprecation-shim.readthedocs.io/en/latest/index.html
|
|
|
|
.. _migration guide: https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html
|
|
|
|
|
2021-02-07 03:45:54 +08:00
|
|
|
Functional unique constraints
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
The new :attr:`*expressions <django.db.models.UniqueConstraint.expressions>`
|
|
|
|
positional argument of
|
|
|
|
:class:`UniqueConstraint() <django.db.models.UniqueConstraint>` enables
|
|
|
|
creating functional unique constraints on expressions and database functions.
|
|
|
|
For example::
|
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
from django.db.models import UniqueConstraint
|
|
|
|
from django.db.models.functions import Lower
|
|
|
|
|
|
|
|
|
|
|
|
class MyModel(models.Model):
|
|
|
|
first_name = models.CharField(max_length=255)
|
|
|
|
last_name = models.CharField(max_length=255)
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
indexes = [
|
|
|
|
UniqueConstraint(
|
|
|
|
Lower('first_name'),
|
|
|
|
Lower('last_name').desc(),
|
|
|
|
name='first_last_name_unique',
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
Functional unique constraints are added to models using the
|
|
|
|
:attr:`Meta.constraints <django.db.models.Options.constraints>` option.
|
|
|
|
|
2020-12-27 10:54:47 +08:00
|
|
|
``scrypt`` password hasher
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
The new :ref:`scrypt password hasher <scrypt-usage>` is more secure and
|
|
|
|
recommended over PBKDF2. However, it's not the default as it requires OpenSSL
|
|
|
|
1.1+ and more memory.
|
|
|
|
|
2021-05-24 08:01:50 +08:00
|
|
|
Redis cache backend
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
The new ``django.core.cache.backends.redis.RedisCache`` cache backend provides
|
|
|
|
built-in support for caching with Redis. `redis-py`_ 3.0.0 or higher is
|
|
|
|
required. For more details, see the :ref:`documentation on caching with Redis
|
|
|
|
in Django <redis>`.
|
|
|
|
|
|
|
|
.. _`redis-py`: https://pypi.org/project/redis/
|
|
|
|
|
2021-09-10 15:06:01 +08:00
|
|
|
Template based form rendering
|
|
|
|
-----------------------------
|
|
|
|
|
|
|
|
To enhance customization of :class:`Forms <django.forms.Form>`,
|
|
|
|
:doc:`Formsets </topics/forms/formsets>`, and
|
|
|
|
:class:`~django.forms.ErrorList` they are now rendered using the template
|
|
|
|
engine. See the new :meth:`~django.forms.Form.render`,
|
|
|
|
:meth:`~django.forms.Form.get_context`, and
|
|
|
|
:attr:`~django.forms.Form.template_name` for ``Form`` and
|
|
|
|
:ref:`formset rendering <formset-rendering>` for ``Formset``.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Minor features
|
|
|
|
--------------
|
|
|
|
|
|
|
|
:mod:`django.contrib.admin`
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2021-01-10 16:00:18 +08:00
|
|
|
* The ``admin/base.html`` template now has a new block ``header`` which
|
|
|
|
contains the admin site header.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2020-11-27 04:51:35 +08:00
|
|
|
* The new :meth:`.ModelAdmin.get_formset_kwargs` method allows customizing the
|
|
|
|
keyword arguments passed to the constructor of a formset.
|
|
|
|
|
2020-12-04 19:50:11 +08:00
|
|
|
* The navigation sidebar now has a quick filter toolbar.
|
|
|
|
|
2020-09-22 16:46:27 +08:00
|
|
|
* The new context variable ``model`` which contains the model class for each
|
|
|
|
model is added to the :meth:`.AdminSite.each_context` method.
|
|
|
|
|
2021-05-20 05:22:26 +08:00
|
|
|
* The new :attr:`.ModelAdmin.search_help_text` attribute allows specifying a
|
|
|
|
descriptive text for the search box.
|
|
|
|
|
2020-11-23 12:37:53 +08:00
|
|
|
* The :attr:`.InlineModelAdmin.verbose_name_plural` attribute now fallbacks to
|
|
|
|
the :attr:`.InlineModelAdmin.verbose_name` + ``'s'``.
|
|
|
|
|
2021-09-20 12:54:35 +08:00
|
|
|
* jQuery is upgraded from version 3.5.1 to 3.6.0.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
:mod:`django.contrib.admindocs`
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2021-02-03 22:31:20 +08:00
|
|
|
* The admindocs now allows esoteric setups where :setting:`ROOT_URLCONF` is not
|
|
|
|
a string.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-02-10 20:33:57 +08:00
|
|
|
* The model section of the ``admindocs`` now shows cached properties.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
:mod:`django.contrib.auth`
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2021-01-14 17:46:29 +08:00
|
|
|
* The default iteration count for the PBKDF2 password hasher is increased from
|
|
|
|
260,000 to 320,000.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2017-06-07 22:48:28 +08:00
|
|
|
* The new
|
|
|
|
:attr:`LoginView.next_page <django.contrib.auth.views.LoginView.next_page>`
|
|
|
|
attribute and
|
|
|
|
:meth:`~django.contrib.auth.views.LoginView.get_default_redirect_url` method
|
|
|
|
allow customizing the redirect after login.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
:mod:`django.contrib.gis`
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2021-04-03 22:23:19 +08:00
|
|
|
* Added support for SpatiaLite 5.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-04-14 22:07:36 +08:00
|
|
|
* :class:`~django.contrib.gis.gdal.GDALRaster` now allows creating rasters in
|
|
|
|
any GDAL virtual filesystem.
|
|
|
|
|
2020-12-10 01:12:56 +08:00
|
|
|
* The new :class:`~django.contrib.gis.admin.GISModelAdmin` class allows
|
|
|
|
customizing the widget used for ``GeometryField``. This is encouraged instead
|
|
|
|
of deprecated ``GeoModelAdmin`` and ``OSMGeoAdmin``.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
:mod:`django.contrib.postgres`
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2020-12-24 06:39:43 +08:00
|
|
|
* The PostgreSQL backend now supports connecting by a service name. See
|
|
|
|
:ref:`postgresql-connection-settings` for more details.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2020-10-17 03:17:13 +08:00
|
|
|
* The new :class:`~django.contrib.postgres.operations.AddConstraintNotValid`
|
|
|
|
operation allows creating check constraints on PostgreSQL without verifying
|
|
|
|
that all existing rows satisfy the new constraint.
|
|
|
|
|
|
|
|
* The new :class:`~django.contrib.postgres.operations.ValidateConstraint`
|
|
|
|
operation allows validating check constraints which were created using
|
|
|
|
:class:`~django.contrib.postgres.operations.AddConstraintNotValid` on
|
|
|
|
PostgreSQL.
|
2020-11-21 04:35:04 +08:00
|
|
|
|
|
|
|
* The new
|
|
|
|
:class:`ArraySubquery() <django.contrib.postgres.expressions.ArraySubquery>`
|
|
|
|
expression allows using subqueries to construct lists of values on
|
|
|
|
PostgreSQL.
|
2020-10-17 03:17:13 +08:00
|
|
|
|
2021-09-15 18:57:49 +08:00
|
|
|
* The new :lookup:`trigram_word_similar` lookup, and the
|
|
|
|
:class:`TrigramWordDistance()
|
|
|
|
<django.contrib.postgres.search.TrigramWordDistance>` and
|
|
|
|
:class:`TrigramWordSimilarity()
|
|
|
|
<django.contrib.postgres.search.TrigramWordSimilarity>` expressions allow
|
|
|
|
using trigram word similarity.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
:mod:`django.contrib.staticfiles`
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2021-01-27 07:10:00 +08:00
|
|
|
* :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` now
|
|
|
|
replaces paths to JavaScript source map references with their hashed
|
|
|
|
counterparts.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-01-05 10:28:01 +08:00
|
|
|
* :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` now
|
|
|
|
replaces paths to JavaScript modules in ``import`` and ``export`` statements
|
|
|
|
with their hashed counterparts.
|
|
|
|
|
2021-06-03 03:44:59 +08:00
|
|
|
* The new ``manifest_storage`` argument of
|
|
|
|
:class:`~django.contrib.staticfiles.storage.ManifestFilesMixin` and
|
|
|
|
:class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`
|
|
|
|
allows customizing the manifest file storage.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Cache
|
|
|
|
~~~~~
|
|
|
|
|
2020-10-16 22:16:55 +08:00
|
|
|
* The new async API for ``django.core.cache.backends.base.BaseCache`` begins
|
|
|
|
the process of making cache backends async-compatible. The new async methods
|
|
|
|
all have ``a`` prefixed names, e.g. ``aadd()``, ``aget()``, ``aset()``,
|
|
|
|
``aget_or_set()``, or ``adelete_many()``.
|
|
|
|
|
|
|
|
Going forward, the ``a`` prefix will be used for async variants of methods
|
|
|
|
generally.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
|
|
|
CSRF
|
|
|
|
~~~~
|
|
|
|
|
2021-01-03 07:46:17 +08:00
|
|
|
* CSRF protection now consults the ``Origin`` header, if present. To facilitate
|
|
|
|
this, :ref:`some changes <csrf-trusted-origins-changes-4.0>` to the
|
|
|
|
:setting:`CSRF_TRUSTED_ORIGINS` setting are required.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
|
|
|
Forms
|
|
|
|
~~~~~
|
|
|
|
|
2021-01-26 14:35:20 +08:00
|
|
|
* :class:`~django.forms.ModelChoiceField` now includes the provided value in
|
|
|
|
the ``params`` argument of a raised
|
|
|
|
:exc:`~django.core.exceptions.ValidationError` for the ``invalid_choice``
|
|
|
|
error message. This allows custom error messages to use the ``%(value)s``
|
|
|
|
placeholder.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-07-08 04:50:30 +08:00
|
|
|
* :class:`~django.forms.formsets.BaseFormSet` now renders non-form errors with
|
|
|
|
an additional class of ``nonform`` to help distinguish them from
|
|
|
|
form-specific errors.
|
|
|
|
|
2021-08-03 18:27:22 +08:00
|
|
|
* :class:`~django.forms.formsets.BaseFormSet` now allows customizing the widget
|
|
|
|
used when deleting forms via
|
|
|
|
:attr:`~django.forms.formsets.BaseFormSet.can_delete` by setting the
|
|
|
|
:attr:`~django.forms.formsets.BaseFormSet.deletion_widget` attribute or
|
|
|
|
overriding :meth:`~django.forms.formsets.BaseFormSet.get_deletion_widget`
|
|
|
|
method.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Generic Views
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
2021-07-13 22:06:12 +08:00
|
|
|
* :class:`~django.views.generic.edit.DeleteView` now uses
|
|
|
|
:class:`~django.views.generic.edit.FormMixin`, allowing you to provide a
|
|
|
|
:class:`~django.forms.Form` subclass, with a checkbox for example, to confirm
|
|
|
|
deletion. In addition, this allows ``DeleteView`` to function with
|
|
|
|
:class:`django.contrib.messages.views.SuccessMessageMixin`.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
|
|
|
Logging
|
|
|
|
~~~~~~~
|
|
|
|
|
2021-07-02 21:36:53 +08:00
|
|
|
* The alias of the database used in an SQL call is now passed as extra context
|
|
|
|
along with each message to the :ref:`django-db-logger` logger.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
|
|
|
Management Commands
|
|
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2020-12-24 23:29:54 +08:00
|
|
|
* The :djadmin:`runserver` management command now supports the
|
|
|
|
:option:`--skip-checks` option.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-02-25 00:16:45 +08:00
|
|
|
* On PostgreSQL, :djadmin:`dbshell` now supports specifying a password file.
|
|
|
|
|
2021-01-19 03:07:07 +08:00
|
|
|
* The :djadmin:`shell` command now respects :py:data:`sys.__interactivehook__`
|
|
|
|
at startup. This allows loading shell history between interactive sessions.
|
|
|
|
As a consequence, ``readline`` is no longer loaded if running in *isolated*
|
|
|
|
mode.
|
|
|
|
|
2021-07-25 07:16:00 +08:00
|
|
|
* The new :attr:`BaseCommand.suppressed_base_arguments
|
|
|
|
<django.core.management.BaseCommand.suppressed_base_arguments>` attribute
|
|
|
|
allows suppressing unsupported default command options in the help output.
|
|
|
|
|
2021-07-24 08:09:03 +08:00
|
|
|
* The new :option:`startapp --exclude` and :option:`startproject --exclude`
|
|
|
|
options allow excluding directories from the template.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Models
|
|
|
|
~~~~~~
|
|
|
|
|
2020-06-09 17:23:31 +08:00
|
|
|
* New :meth:`QuerySet.contains(obj) <.QuerySet.contains>` method returns
|
|
|
|
whether the queryset contains the given object. This tries to perform the
|
|
|
|
query in the simplest and fastest way possible.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-03-25 06:29:33 +08:00
|
|
|
* The new ``precision`` argument of the
|
|
|
|
:class:`Round() <django.db.models.functions.Round>` database function allows
|
|
|
|
specifying the number of decimal places after rounding.
|
|
|
|
|
2021-04-07 00:20:31 +08:00
|
|
|
* :meth:`.QuerySet.bulk_create` now sets the primary key on objects when using
|
|
|
|
SQLite 3.35+.
|
|
|
|
|
2021-04-07 00:14:16 +08:00
|
|
|
* :class:`~django.db.models.DurationField` now supports multiplying and
|
|
|
|
dividing by scalar values on SQLite.
|
|
|
|
|
2021-06-26 13:18:38 +08:00
|
|
|
* :meth:`.QuerySet.bulk_update` now returns the number of objects updated.
|
|
|
|
|
2021-05-22 10:32:16 +08:00
|
|
|
* The new :attr:`.Aggregate.empty_aggregate_value` attribute allows specifying
|
|
|
|
a value to return when the aggregation is used over an empty result set.
|
|
|
|
|
2021-07-08 12:51:10 +08:00
|
|
|
* The ``skip_locked`` argument of :meth:`.QuerySet.select_for_update()` is now
|
|
|
|
allowed on MariaDB 10.6+.
|
|
|
|
|
2021-04-03 01:25:20 +08:00
|
|
|
* :class:`~django.db.models.Lookup` expressions may now be used in ``QuerySet``
|
|
|
|
annotations, aggregations, and directly in filters.
|
|
|
|
|
2021-02-21 09:38:55 +08:00
|
|
|
* The new :ref:`default <aggregate-default>` argument for built-in aggregates
|
|
|
|
allows specifying a value to be returned when the queryset (or grouping)
|
|
|
|
contains no entries, rather than ``None``.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Requests and Responses
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
2020-08-27 00:09:19 +08:00
|
|
|
* The :class:`~django.middleware.security.SecurityMiddleware` now adds the
|
|
|
|
:ref:`Cross-Origin Opener Policy <cross-origin-opener-policy>` header with a
|
|
|
|
value of ``'same-origin'`` to prevent cross-origin popups from sharing the
|
|
|
|
same browsing context. You can prevent this header from being added by
|
|
|
|
setting the :setting:`SECURE_CROSS_ORIGIN_OPENER_POLICY` setting to ``None``.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
|
|
|
Signals
|
|
|
|
~~~~~~~
|
|
|
|
|
2021-01-29 23:19:06 +08:00
|
|
|
* The new ``stdout`` argument for :func:`~django.db.models.signals.pre_migrate`
|
|
|
|
and :func:`~django.db.models.signals.post_migrate` signals allows redirecting
|
|
|
|
output to a stream-like object. It should be preferred over
|
|
|
|
:py:data:`sys.stdout` and :py:func:`print` when emitting verbose output in
|
|
|
|
order to allow proper capture when testing.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
|
|
|
Templates
|
|
|
|
~~~~~~~~~
|
|
|
|
|
2021-09-08 14:37:27 +08:00
|
|
|
* :tfilter:`floatformat` template filter now allows using the ``u`` suffix to
|
|
|
|
force disabling localization.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
|
|
|
Tests
|
|
|
|
~~~~~
|
|
|
|
|
2021-02-15 11:42:47 +08:00
|
|
|
* The new ``serialized_aliases`` argument of
|
|
|
|
:func:`django.test.utils.setup_databases` determines which
|
|
|
|
:setting:`DATABASES` aliases test databases should have their state
|
|
|
|
serialized to allow usage of the
|
|
|
|
:ref:`serialized_rollback <test-case-serialized-rollback>` feature.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-03-16 20:45:53 +08:00
|
|
|
* Django test runner now supports a :option:`--buffer <test --buffer>` option
|
|
|
|
with parallel tests.
|
|
|
|
|
2021-08-10 01:18:51 +08:00
|
|
|
* The new ``logger`` argument to :class:`~django.test.runner.DiscoverRunner`
|
|
|
|
allows a Python :py:ref:`logger <logger>` to be used for logging.
|
|
|
|
|
|
|
|
* The new :meth:`.DiscoverRunner.log` method provides a way to log messages
|
|
|
|
that uses the ``DiscoverRunner.logger``, or prints to the console if not set.
|
2021-03-19 17:20:08 +08:00
|
|
|
|
2021-04-25 07:46:16 +08:00
|
|
|
* Django test runner now supports a :option:`--shuffle <test --shuffle>` option
|
|
|
|
to execute tests in a random order.
|
|
|
|
|
2020-05-24 02:32:22 +08:00
|
|
|
* The :option:`test --parallel` option now supports the value ``auto`` to run
|
|
|
|
one test process for each processor core.
|
|
|
|
|
2021-08-25 04:29:55 +08:00
|
|
|
* :meth:`.TestCase.captureOnCommitCallbacks` now captures new callbacks added
|
|
|
|
while executing :func:`.transaction.on_commit` callbacks.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
.. _backwards-incompatible-4.0:
|
|
|
|
|
|
|
|
Backwards incompatible changes in 4.0
|
|
|
|
=====================================
|
|
|
|
|
|
|
|
Database backend API
|
|
|
|
--------------------
|
|
|
|
|
|
|
|
This section describes changes that may be needed in third-party database
|
|
|
|
backends.
|
|
|
|
|
2021-03-18 19:59:55 +08:00
|
|
|
* ``DatabaseOperations.year_lookup_bounds_for_date_field()`` and
|
|
|
|
``year_lookup_bounds_for_datetime_field()`` methods now take the optional
|
|
|
|
``iso_year`` argument in order to support bounds for ISO-8601 week-numbering
|
|
|
|
years.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-05-28 03:35:24 +08:00
|
|
|
* The second argument of ``DatabaseSchemaEditor._unique_sql()`` and
|
|
|
|
``_create_unique_sql()`` methods is now fields instead of columns.
|
|
|
|
|
2021-01-19 19:25:20 +08:00
|
|
|
:mod:`django.contrib.gis`
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
* Support for PostGIS 2.3 is removed.
|
|
|
|
|
2021-04-07 23:38:37 +08:00
|
|
|
* Support for GDAL 2.0 and GEOS 3.5 is removed.
|
|
|
|
|
2021-01-19 19:25:20 +08:00
|
|
|
Dropped support for PostgreSQL 9.6
|
|
|
|
----------------------------------
|
|
|
|
|
|
|
|
Upstream support for PostgreSQL 9.6 ends in November 2021. Django 4.0 supports
|
|
|
|
PostgreSQL 10 and higher.
|
|
|
|
|
2021-01-29 14:03:40 +08:00
|
|
|
Dropped support for Oracle 12.2 and 18c
|
|
|
|
---------------------------------------
|
|
|
|
|
|
|
|
Upstream support for Oracle 12.2 ends in March 2022 and for Oracle 18c it ends
|
|
|
|
in June 2021. Django 3.2 will be supported until April 2024. Django 4.0
|
|
|
|
officially supports Oracle 19c.
|
|
|
|
|
2021-01-13 08:55:02 +08:00
|
|
|
.. _csrf-trusted-origins-changes-4.0:
|
|
|
|
|
|
|
|
``CSRF_TRUSTED_ORIGINS`` changes
|
|
|
|
--------------------------------
|
|
|
|
|
|
|
|
Format change
|
|
|
|
~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
Values in the :setting:`CSRF_TRUSTED_ORIGINS` setting must include the scheme
|
|
|
|
(e.g. ``'http://'`` or ``'https://'``) instead of only the hostname.
|
|
|
|
|
|
|
|
Also, values that started with a dot, must now also include an asterisk before
|
|
|
|
the dot. For example, change ``'.example.com'`` to ``'https://*.example.com'``.
|
|
|
|
|
|
|
|
A system check detects any required changes.
|
|
|
|
|
2021-01-03 07:46:17 +08:00
|
|
|
Configuring it may now be required
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
As CSRF protection now consults the ``Origin`` header, you may need to set
|
|
|
|
:setting:`CSRF_TRUSTED_ORIGINS`, particularly if you allow requests from
|
|
|
|
subdomains by setting :setting:`CSRF_COOKIE_DOMAIN` (or
|
|
|
|
:setting:`SESSION_COOKIE_DOMAIN` if :setting:`CSRF_USE_SESSIONS` is enabled) to
|
|
|
|
a value starting with a dot.
|
|
|
|
|
2021-04-23 20:59:35 +08:00
|
|
|
``SecurityMiddleware`` no longer sets the ``X-XSS-Protection`` header
|
|
|
|
---------------------------------------------------------------------
|
|
|
|
|
|
|
|
The :class:`~django.middleware.security.SecurityMiddleware` no longer sets the
|
|
|
|
``X-XSS-Protection`` header if the ``SECURE_BROWSER_XSS_FILTER`` setting is
|
|
|
|
``True``. The setting is removed.
|
|
|
|
|
|
|
|
Most modern browsers don't honor the ``X-XSS-Protection`` HTTP header. You can
|
|
|
|
use Content-Security-Policy_ without allowing ``'unsafe-inline'`` scripts
|
|
|
|
instead.
|
|
|
|
|
|
|
|
If you want to support legacy browsers and set the header, use this line in a
|
|
|
|
custom middleware::
|
|
|
|
|
|
|
|
response.headers.setdefault('X-XSS-Protection', '1; mode=block')
|
|
|
|
|
|
|
|
.. _Content-Security-Policy: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
|
|
|
|
|
2021-04-29 03:15:26 +08:00
|
|
|
Migrations autodetector changes
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
The migrations autodetector now uses model states instead of model classes.
|
|
|
|
Also, migration operations for ``ForeignKey`` and ``ManyToManyField`` fields no
|
|
|
|
longer specify attributes which were not passed to the fields during
|
|
|
|
initialization.
|
|
|
|
|
|
|
|
As a side-effect, running ``makemigrations`` might generate no-op
|
|
|
|
``AlterField`` operations for ``ManyToManyField`` and ``ForeignKey`` fields in
|
|
|
|
some cases.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Miscellaneous
|
|
|
|
-------------
|
|
|
|
|
2021-01-29 20:07:05 +08:00
|
|
|
* Support for ``cx_Oracle`` < 7.0 is removed.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-02-14 03:07:55 +08:00
|
|
|
* To allow serving a Django site on a subpath without changing the value of
|
|
|
|
:setting:`STATIC_URL`, the leading slash is removed from that setting (now
|
|
|
|
``'static/'``) in the default :djadmin:`startproject` template.
|
2021-01-29 22:14:21 +08:00
|
|
|
|
2021-03-03 16:13:07 +08:00
|
|
|
* The :class:`~django.contrib.admin.AdminSite` method for the admin ``index``
|
|
|
|
view is no longer decorated with ``never_cache`` when accessed directly,
|
|
|
|
rather than via the recommended ``AdminSite.urls`` property, or
|
|
|
|
``AdminSite.get_urls()`` method.
|
|
|
|
|
2021-03-10 16:16:28 +08:00
|
|
|
* Unsupported operations on a sliced queryset now raise ``TypeError`` instead
|
|
|
|
of ``AssertionError``.
|
|
|
|
|
2021-03-09 00:29:44 +08:00
|
|
|
* The undocumented ``django.test.runner.reorder_suite()`` function is renamed
|
|
|
|
to ``reorder_tests()``. It now accepts an iterable of tests rather than a
|
|
|
|
test suite, and returns an iterator of tests.
|
|
|
|
|
2021-03-16 23:41:27 +08:00
|
|
|
* Calling ``FileSystemStorage.delete()`` with an empty ``name`` now raises
|
|
|
|
``ValueError`` instead of ``AssertionError``.
|
|
|
|
|
|
|
|
* Calling ``EmailMultiAlternatives.attach_alternative()`` or
|
|
|
|
``EmailMessage.attach()`` with an invalid ``content`` or ``mimetype``
|
|
|
|
arguments now raise ``ValueError`` instead of ``AssertionError``.
|
|
|
|
|
2021-03-19 07:43:38 +08:00
|
|
|
* :meth:`~django.test.SimpleTestCase.assertHTMLEqual` no longer considers a
|
|
|
|
non-boolean attribute without a value equal to an attribute with the same
|
|
|
|
name and value.
|
|
|
|
|
2021-03-26 20:14:43 +08:00
|
|
|
* Tests that fail to load, for example due to syntax errors, now always match
|
|
|
|
when using :option:`test --tag`.
|
|
|
|
|
2021-04-29 18:04:30 +08:00
|
|
|
* The undocumented ``django.contrib.admin.utils.lookup_needs_distinct()``
|
|
|
|
function is renamed to ``lookup_spawns_duplicates()``.
|
|
|
|
|
2021-04-29 20:35:11 +08:00
|
|
|
* The undocumented ``HttpRequest.get_raw_uri()`` method is removed. The
|
|
|
|
:meth:`.HttpRequest.build_absolute_uri` method may be a suitable alternative.
|
|
|
|
|
2021-05-20 03:07:48 +08:00
|
|
|
* The ``object`` argument of undocumented ``ModelAdmin.log_addition()``,
|
|
|
|
``log_change()``, and ``log_deletion()`` methods is renamed to ``obj``.
|
|
|
|
|
2021-05-27 01:21:19 +08:00
|
|
|
* :class:`~django.utils.feedgenerator.RssFeed`,
|
|
|
|
:class:`~django.utils.feedgenerator.Atom1Feed`, and their subclasses now
|
|
|
|
emit elements with no content as self-closing tags.
|
|
|
|
|
2021-06-07 19:56:50 +08:00
|
|
|
* ``NodeList.render()`` no longer casts the output of ``render()`` method for
|
|
|
|
individual nodes to a string. ``Node.render()`` should always return a string
|
|
|
|
as documented.
|
|
|
|
|
2021-07-21 03:38:17 +08:00
|
|
|
* The ``where_class`` property of ``django.db.models.sql.query.Query`` and the
|
|
|
|
``where_class`` argument to the private ``get_extra_restriction()`` method of
|
|
|
|
``ForeignObject`` and ``ForeignObjectRel`` are removed. If needed, initialize
|
|
|
|
``django.db.models.sql.where.WhereNode`` instead.
|
|
|
|
|
2021-07-18 04:54:36 +08:00
|
|
|
* The ``filter_clause`` argument of the undocumented ``Query.add_filter()``
|
|
|
|
method is replaced by two positional arguments ``filter_lhs`` and
|
|
|
|
``filter_rhs``.
|
|
|
|
|
2021-07-23 13:54:57 +08:00
|
|
|
* :class:`~django.middleware.csrf.CsrfViewMiddleware` now uses
|
|
|
|
``request.META['CSRF_COOKIE_NEEDS_UPDATE']`` in place of
|
|
|
|
``request.META['CSRF_COOKIE_USED']``, ``request.csrf_cookie_needs_reset``,
|
|
|
|
and ``response.csrf_cookie_set`` to track whether the CSRF cookie should be
|
|
|
|
sent. This is an undocumented, private API.
|
|
|
|
|
2021-08-05 11:20:04 +08:00
|
|
|
* The undocumented ``TRANSLATOR_COMMENT_MARK`` constant is moved from
|
|
|
|
``django.template.base`` to ``django.utils.translation.template``.
|
|
|
|
|
2021-08-12 13:50:54 +08:00
|
|
|
* The ``real_apps`` argument of the undocumented
|
|
|
|
``django.db.migrations.state.ProjectState.__init__()`` method must now be a
|
|
|
|
set if provided.
|
|
|
|
|
2021-06-11 14:39:12 +08:00
|
|
|
* :class:`~django.forms.RadioSelect` and
|
|
|
|
:class:`~django.forms.CheckboxSelectMultiple` widgets are now rendered in
|
|
|
|
``<div>`` tags so they are announced more concisely by screen readers. If you
|
|
|
|
need the previous behavior, :ref:`override the widget template
|
|
|
|
<overriding-built-in-widget-templates>` with the appropriate template from
|
|
|
|
Django 3.2.
|
|
|
|
|
2021-09-08 14:37:27 +08:00
|
|
|
* The :tfilter:`floatformat` template filter no longer depends on the
|
2021-09-09 13:42:05 +08:00
|
|
|
``USE_L10N`` setting and always returns localized output. Use the ``u``
|
|
|
|
suffix to disable localization.
|
|
|
|
|
|
|
|
* The default value of the ``USE_L10N`` setting is changed to ``True``. See the
|
|
|
|
:ref:`Localization section <use_l10n_deprecation>` above for more details.
|
2021-09-08 14:37:27 +08:00
|
|
|
|
2021-09-09 21:15:44 +08:00
|
|
|
* As part of the :ref:`move to zoneinfo <whats-new-4.0>`,
|
|
|
|
:attr:`django.utils.timezone.utc` is changed to alias
|
|
|
|
:attr:`datetime.timezone.utc`.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
.. _deprecated-features-4.0:
|
|
|
|
|
|
|
|
Features deprecated in 4.0
|
|
|
|
==========================
|
|
|
|
|
2021-09-09 21:15:44 +08:00
|
|
|
Use of ``pytz`` time zones
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
As part of the :ref:`move to zoneinfo <whats-new-4.0>`, use of ``pytz`` time
|
|
|
|
zones is deprecated.
|
|
|
|
|
|
|
|
Accordingly, the ``is_dst`` arguments to the following are also deprecated:
|
|
|
|
|
|
|
|
* :meth:`django.db.models.query.QuerySet.datetimes()`
|
|
|
|
* :func:`django.db.models.functions.Trunc()`
|
|
|
|
* :func:`django.db.models.functions.TruncSecond()`
|
|
|
|
* :func:`django.db.models.functions.TruncMinute()`
|
|
|
|
* :func:`django.db.models.functions.TruncHour()`
|
|
|
|
* :func:`django.db.models.functions.TruncDay()`
|
|
|
|
* :func:`django.db.models.functions.TruncWeek()`
|
|
|
|
* :func:`django.db.models.functions.TruncMonth()`
|
|
|
|
* :func:`django.db.models.functions.TruncQuarter()`
|
|
|
|
* :func:`django.db.models.functions.TruncYear()`
|
|
|
|
* :func:`django.utils.timezone.make_aware()`
|
|
|
|
|
|
|
|
Support for use of ``pytz`` will be removed in Django 5.0.
|
|
|
|
|
2021-05-14 21:58:45 +08:00
|
|
|
Time zone support
|
|
|
|
-----------------
|
|
|
|
|
|
|
|
In order to follow good practice, the default value of the :setting:`USE_TZ`
|
|
|
|
setting will change from ``False`` to ``True``, and time zone support will be
|
|
|
|
enabled by default, in Django 5.0.
|
|
|
|
|
|
|
|
Note that the default :file:`settings.py` file created by
|
|
|
|
:djadmin:`django-admin startproject <startproject>` includes
|
|
|
|
:setting:`USE_TZ = True <USE_TZ>` since Django 1.4.
|
|
|
|
|
|
|
|
You can set ``USE_TZ`` to ``False`` in your project settings before then to
|
|
|
|
opt-out.
|
|
|
|
|
2021-09-09 13:42:05 +08:00
|
|
|
.. _use_l10n_deprecation:
|
|
|
|
|
|
|
|
Localization
|
|
|
|
------------
|
|
|
|
|
|
|
|
In order to follow good practice, the default value of the ``USE_L10N`` setting
|
|
|
|
is changed from ``False`` to ``True``.
|
|
|
|
|
|
|
|
Moreover ``USE_L10N`` is deprecated as of this release. Starting with Django
|
|
|
|
5.0, by default, any date or number displayed by Django will be localized.
|
|
|
|
|
|
|
|
The :ttag:`{% localize %} <localize>` tag and the :tfilter:`localize`/
|
|
|
|
:tfilter:`unlocalize` filters will still be honored by Django.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Miscellaneous
|
|
|
|
-------------
|
|
|
|
|
2021-02-15 11:42:47 +08:00
|
|
|
* ``SERIALIZE`` test setting is deprecated as it can be inferred from the
|
|
|
|
:attr:`~django.test.TestCase.databases` with the
|
|
|
|
:ref:`serialized_rollback <test-case-serialized-rollback>` option enabled.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-05-06 05:28:08 +08:00
|
|
|
* The undocumented ``django.utils.baseconv`` module is deprecated.
|
|
|
|
|
2021-05-08 01:20:14 +08:00
|
|
|
* The undocumented ``django.utils.datetime_safe`` module is deprecated.
|
|
|
|
|
2021-05-15 14:11:14 +08:00
|
|
|
* The default sitemap protocol for sitemaps built outside the context of a
|
|
|
|
request will change from ``'http'`` to ``'https'`` in Django 5.0.
|
|
|
|
|
2021-07-16 05:56:41 +08:00
|
|
|
* The ``extra_tests`` argument for :meth:`.DiscoverRunner.build_suite` and
|
|
|
|
:meth:`.DiscoverRunner.run_tests` is deprecated.
|
|
|
|
|
2021-06-30 07:08:27 +08:00
|
|
|
* The :class:`~django.contrib.postgres.aggregates.ArrayAgg`,
|
|
|
|
:class:`~django.contrib.postgres.aggregates.JSONBAgg`, and
|
|
|
|
:class:`~django.contrib.postgres.aggregates.StringAgg` aggregates will return
|
|
|
|
``None`` when there are no rows instead of ``[]``, ``[]``, and ``''``
|
|
|
|
respectively in Django 5.0. If you need the previous behavior, explicitly set
|
|
|
|
``default`` to ``Value([])``, ``Value('[]')``, or ``Value('')``.
|
|
|
|
|
2020-12-10 01:12:56 +08:00
|
|
|
* The ``django.contrib.gis.admin.GeoModelAdmin`` and ``OSMGeoAdmin`` classes
|
|
|
|
are deprecated. Use :class:`~django.contrib.admin.ModelAdmin` and
|
|
|
|
:class:`~django.contrib.gis.admin.GISModelAdmin` instead.
|
|
|
|
|
2021-09-10 15:06:01 +08:00
|
|
|
* Since form rendering now uses the template engine, the undocumented
|
|
|
|
``BaseForm._html_output()`` helper method is deprecated.
|
|
|
|
|
|
|
|
* The ability to return a ``str`` from ``ErrorList`` and ``ErrorDict`` is
|
|
|
|
deprecated. It is expected these methods return a ``SafeString``.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
Features removed in 4.0
|
|
|
|
=======================
|
|
|
|
|
|
|
|
These features have reached the end of their deprecation cycle and are removed
|
|
|
|
in Django 4.0.
|
|
|
|
|
|
|
|
See :ref:`deprecated-features-3.0` for details on these changes, including how
|
|
|
|
to remove usage of these features.
|
|
|
|
|
2021-01-05 19:18:04 +08:00
|
|
|
* ``django.utils.http.urlquote()``, ``urlquote_plus()``, ``urlunquote()``, and
|
|
|
|
``urlunquote_plus()`` are removed.
|
2021-01-05 18:07:46 +08:00
|
|
|
|
2021-01-05 19:27:52 +08:00
|
|
|
* ``django.utils.encoding.force_text()`` and ``smart_text()`` are removed.
|
|
|
|
|
2021-01-05 19:45:08 +08:00
|
|
|
* ``django.utils.translation.ugettext()``, ``ugettext_lazy()``,
|
|
|
|
``ugettext_noop()``, ``ungettext()``, and ``ungettext_lazy()`` are removed.
|
|
|
|
|
2021-01-06 20:16:24 +08:00
|
|
|
* ``django.views.i18n.set_language()`` doesn't set the user language in
|
|
|
|
``request.session`` (key ``_language``).
|
|
|
|
|
2021-01-07 14:55:06 +08:00
|
|
|
* ``alias=None`` is required in the signature of
|
|
|
|
``django.db.models.Expression.get_group_by_cols()`` subclasses.
|
|
|
|
|
2021-01-07 15:09:04 +08:00
|
|
|
* ``django.utils.text.unescape_entities()`` is removed.
|
|
|
|
|
2021-01-07 15:15:39 +08:00
|
|
|
* ``django.utils.http.is_safe_url()`` is removed.
|
|
|
|
|
2021-01-05 18:07:46 +08:00
|
|
|
See :ref:`deprecated-features-3.1` for details on these changes, including how
|
|
|
|
to remove usage of these features.
|
|
|
|
|
2021-01-07 20:10:37 +08:00
|
|
|
* The ``PASSWORD_RESET_TIMEOUT_DAYS`` setting is removed.
|
2021-01-08 03:50:36 +08:00
|
|
|
|
|
|
|
* The :lookup:`isnull` lookup no longer allows using non-boolean values as the
|
|
|
|
right-hand side.
|
2021-01-08 03:56:49 +08:00
|
|
|
|
|
|
|
* The ``django.db.models.query_utils.InvalidQuery`` exception class is removed.
|
2021-01-10 03:31:27 +08:00
|
|
|
|
|
|
|
* The ``django-admin.py`` entry point is removed.
|
2021-01-11 19:27:40 +08:00
|
|
|
|
|
|
|
* The ``HttpRequest.is_ajax()`` method is removed.
|
2021-01-11 19:49:16 +08:00
|
|
|
|
|
|
|
* Support for the pre-Django 3.1 encoding format of cookies values used by
|
|
|
|
``django.contrib.messages.storage.cookie.CookieStorage`` is removed.
|
2021-01-12 03:31:49 +08:00
|
|
|
|
|
|
|
* Support for the pre-Django 3.1 password reset tokens in the admin site (that
|
|
|
|
use the SHA-1 hashing algorithm) is removed.
|
2021-01-12 04:27:01 +08:00
|
|
|
|
|
|
|
* Support for the pre-Django 3.1 encoding format of sessions is removed.
|
2021-01-12 04:57:48 +08:00
|
|
|
|
|
|
|
* Support for the pre-Django 3.1 ``django.core.signing.Signer`` signatures
|
|
|
|
(encoded with the SHA-1 algorithm) is removed.
|
|
|
|
|
|
|
|
* Support for the pre-Django 3.1 ``django.core.signing.dumps()`` signatures
|
|
|
|
(encoded with the SHA-1 algorithm) in ``django.core.signing.loads()`` is
|
|
|
|
removed.
|
2021-01-13 03:31:36 +08:00
|
|
|
|
|
|
|
* Support for the pre-Django 3.1 user sessions (that use the SHA-1 algorithm)
|
|
|
|
is removed.
|
2021-01-13 03:55:32 +08:00
|
|
|
|
2021-05-27 03:01:09 +08:00
|
|
|
* The ``get_response`` argument for
|
2021-01-13 03:55:32 +08:00
|
|
|
``django.utils.deprecation.MiddlewareMixin.__init__()`` is required and
|
|
|
|
doesn't accept ``None``.
|
2021-01-13 18:08:32 +08:00
|
|
|
|
|
|
|
* The ``providing_args`` argument for ``django.dispatch.Signal`` is removed.
|
2021-01-13 19:29:58 +08:00
|
|
|
|
2021-01-14 05:33:42 +08:00
|
|
|
* The ``length`` argument for ``django.utils.crypto.get_random_string()`` is
|
|
|
|
required.
|
|
|
|
|
2021-01-13 19:29:58 +08:00
|
|
|
* The ``list`` message for ``ModelMultipleChoiceField`` is removed.
|
2021-01-13 19:52:13 +08:00
|
|
|
|
|
|
|
* Support for passing raw column aliases to ``QuerySet.order_by()`` is removed.
|
2021-01-14 04:28:09 +08:00
|
|
|
|
|
|
|
* The ``NullBooleanField`` model field is removed, except for support in
|
|
|
|
historical migrations.
|
2021-01-14 16:06:39 +08:00
|
|
|
|
|
|
|
* ``django.conf.urls.url()`` is removed.
|
2021-01-14 16:33:12 +08:00
|
|
|
|
|
|
|
* The ``django.contrib.postgres.fields.JSONField`` model field is removed,
|
|
|
|
except for support in historical migrations.
|
2021-01-14 16:57:22 +08:00
|
|
|
|
|
|
|
* ``django.contrib.postgres.fields.jsonb.KeyTransform`` and
|
|
|
|
``django.contrib.postgres.fields.jsonb.KeyTextTransform`` are removed.
|
2021-01-14 17:04:20 +08:00
|
|
|
|
|
|
|
* ``django.contrib.postgres.forms.JSONField`` is removed.
|
2021-01-14 17:14:57 +08:00
|
|
|
|
|
|
|
* The ``{% ifequal %}`` and ``{% ifnotequal %}`` template tags are removed.
|
2021-01-14 17:27:04 +08:00
|
|
|
|
|
|
|
* The ``DEFAULT_HASHING_ALGORITHM`` transitional setting is removed.
|