August 3, 2022
Welcome to Django 4.1!
These release notes cover the new features, as well as some backwards incompatible changes you'll want to be aware of when upgrading from Django 4.0 or earlier. We've begun the deprecation process for some features.
如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。
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.
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 Asynchronous class-based views for more details.
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 Asynchronous queries for details and limitations.
Check,
unique, and exclusion constraints defined
in the Meta.constraints option
are now checked during model validation.
In order to aid users with screen readers, and other assistive technology, new
<div> 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
FORM_RENDERER setting.
See the Forms section (below) for full details.
CSRF_COOKIE_MASKED setting¶The new CSRF_COOKIE_MASKED transitional setting allows specifying
whether to mask the CSRF cookie.
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.
django.contrib.admin¶FieldListFilter
subclasses can now control the query string value separator when filtering
for multiple values using the __in lookup.history view
is now paginated.AdminSite.get_app_list() method now allows changing the order of
apps and models on the admin index page.django.contrib.auth¶RemoteUserBackend.configure_user() method now allows synchronizing
user attributes with attributes in a remote system such as an LDAP directory.django.contrib.gis¶GEOSGeometry.make_valid() method allows converting invalid
geometries to valid ones.clone argument for GEOSGeometry.normalize() allows
creating a normalized clone of the geometry.django.contrib.postgres¶BitXor()
aggregate function returns an int of the bitwise XOR of all non-null
input values.SpGistIndex now supports covering
indexes on PostgreSQL 14+.ExclusionConstraint now
supports covering exclusion constraints using SP-GiST indexes on PostgreSQL
14+.default_bounds attribute of DateTimeRangeField and
DecimalRangeField allows
specifying bounds for list and tuple inputs.ExclusionConstraint now allows
specifying operator classes with the
OpClass() expression.django.contrib.sitemaps¶<sitemapindex> now includes the
<lastmod> timestamp where available, through the new
get_latest_lastmod() method. Custom
sitemap index templates should be updated for the adjusted context
variables.django.contrib.staticfiles¶ManifestStaticFilesStorage now
replaces paths to CSS source map references with their hashed counterparts.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.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 form_template_name on
the class provided for FORM_RENDERER.
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
formset_template_name renderer
attribute.
The new div.html form template, referencing
Form.template_name_div attribute, and matching Form.as_div()
method, render forms using HTML <div> elements.
This new output style is recommended over the existing
as_table(), as_p() and as_ul() styles,
as the template implements <fieldset> and <legend> 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 <div> 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 FORM_RENDERER setting. For
example:
FORM_RENDERER = "django.forms.renderers.DjangoDivFormRenderer"
Once the <div> 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 <div> output style is not appropriate for your project, you should
define a renderer subclass specifying
form_template_name and
formset_template_name for your
required style, and set FORM_RENDERER accordingly.
For example, for the <p> output style used by 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 legend_tag() allows rendering field
labels in <legend> tags via the new tag argument of
label_tag().
The new edit_only argument for modelformset_factory() and
inlineformset_factory() allows preventing new objects creation.
The js and css class attributes of Media
now allow using hashable objects, not only path strings, as long as those
objects implement the __html__() method (typically when decorated with
the html_safe() decorator).
The new BoundField.use_fieldset and Widget.use_fieldset
attributes help to identify widgets where its inputs should be grouped in a
<fieldset> with a <legend>.
The error_messages argument for
BaseFormSet now allows customizing
error messages for invalid number of forms by passing 'too_few_forms'
and 'too_many_forms' keys.
IntegerField, FloatField, and
DecimalField now optionally accept a step_size
argument. This is used to set the step HTML attribute, and is validated
on form submission.
i18n_patterns() function now supports
languages with both scripts and regions.makemigrations --no-input now logs default answers and reasons why
migrations cannot be created.makemigrations --scriptable option diverts log output and
input prompts to stderr, writing only paths of generated migration files
to stdout.migrate --prune option allows deleting nonexistent
migrations from the django_migrations table.startproject, startapp,
optimizemigration, makemigrations, and
squashmigrations are now formatted using the black command if
it is present on your PATH.optimizemigration command allows optimizing operations for
a migration.RenameIndex operation
allows renaming indexes defined in the
Meta.indexes or
index_together options.RenameIndex operations instead of
RemoveIndex and AddIndex, when renaming indexes defined in the
Meta.indexes.RenameIndex operations instead of
AlterIndexTogether and AddIndex, when moving indexes defined in the
Meta.index_together to the
Meta.indexes.order_by argument of the
Window expression now accepts string
references to fields and transforms.CONN_HEALTH_CHECKS setting allows enabling health checks
for persistent database connections
in order to reduce the number of failed requests, e.g. after database server
restart.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+.QuerySet.iterator() now supports prefetching related objects as long
as the chunk_size argument is provided. In older versions, no prefetching
was done.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.AutoField, BigAutoField, and SmallAutoField are
now created as identity columns rather than serial columns with sequences.HttpResponse.set_cookie() now supports timedelta
objects for the max_age argument.SECRET_KEY_FALLBACKS setting allows providing a list of
values for secret key rotation.SECURE_PROXY_SSL_HEADER setting now supports a comma-separated
list of protocols in the header value.pre_delete and
post_delete signals now dispatch the
origin of the deletion.<script> element id attribute is no longer required when
wrapping the json_script template filter.cached template loader
is now enabled in development, when DEBUG is True, and
OPTIONS['loaders'] isn't specified. You may
specify OPTIONS['loaders'] to override this, if necessary.DiscoverRunner now supports running tests in parallel on
macOS, Windows, and any other systems where the default
multiprocessing start method is spawn.django.test.TestCase now
raises a RuntimeError, the same as outside of tests.SimpleTestCase.assertFormError() and
assertFormsetError()
now support passing a form/formset object directly.ResolverMatch.captured_kwargs attribute stores the captured
keyword arguments, as parsed from the URL.ResolverMatch.extra_kwargs attribute stores the additional
keyword arguments passed to the view function.SimpleLazyObject now supports addition operations.mark_safe() now preserves lazy objects.StepValueValidator checks if a value
is an integral multiple of a given step size. This new validator is used for
the new step_size argument added to form fields representing numeric
values.本节介绍了第三方数据库后端可能需要的更改。
BaseDatabaseFeatures.has_case_insensitive_like is changed from True
to False to reflect the behavior of most databases.DatabaseIntrospection.get_key_columns() is removed. Use
DatabaseIntrospection.get_relations() instead.DatabaseOperations.ignore_conflicts_suffix_sql() method is replaced by
DatabaseOperations.on_conflict_suffix_sql() that accepts the fields,
on_conflict, update_fields, and unique_fields arguments.ignore_conflicts argument of the
DatabaseOperations.insert_statement() method is replaced by
on_conflict that accepts django.db.models.constants.OnConflict.DatabaseOperations._convert_field_to_tz() is replaced by
DatabaseOperations._convert_sql_to_tz() that accepts the sql,
params, and tzname arguments.DatabaseOperations now take sql and
params arguments instead of field_name and return 2-tuple containing
some SQL and the parameters to be interpolated into that SQL. The changed
methods have these new signatures:DatabaseOperations.date_extract_sql(lookup_type, sql, params)DatabaseOperations.datetime_extract_sql(lookup_type, sql, params, tzname)DatabaseOperations.time_extract_sql(lookup_type, sql, params)DatabaseOperations.date_trunc_sql(lookup_type, sql, params, tzname=None)DatabaseOperations.datetime_trunc_sql(self, lookup_type, sql, params, tzname)DatabaseOperations.time_trunc_sql(lookup_type, sql, params, tzname=None)DatabaseOperations.datetime_cast_date_sql(sql, params, tzname)DatabaseOperations.datetime_cast_time_sql(sql, params, tzname)django.contrib.gis¶Upstream support for PostgreSQL 10 ends in November 2022. Django 4.1 supports PostgreSQL 11 and higher.
Upstream support for MariaDB 10.2 ends in May 2022. Django 4.1 supports MariaDB 10.3 and higher.
Admin changelist searches using multiple search terms are now applied in a
single call to filter(), rather than in sequential filter() calls.
For multi-valued relationships, this means that rows from the related model
must match all terms rather than any term. For example, if search_fields
is set to ['child__name', 'child__age'], and a user searches for
'Jamal 17', parent rows will be returned only if there is a relationship to
some 17-year-old child named Jamal, rather than also returning parents who
merely have a younger or older child named Jamal in addition to some other
17-year-old.
See the 跨多值关联 topic for more discussion of
this difference. In Django 4.0 and earlier,
get_search_results() followed the
second example query, but this undocumented behavior led to queries with
excessive joins.
In order to unify the behavior with many-to-many relations for unsaved model
instances, a reverse foreign key now raises ValueError when calling
related managers for
unsaved objects.
ForeignKey,
ManyToManyField, and
GenericRelation are now cached
on the Model instance to which they belong. This
change was reverted in Django 4.1.2.unittest.expectedFailure().CsrfViewMiddleware no longer masks the CSRF
cookie like it does the CSRF token in the DOM.CsrfViewMiddleware now uses
request.META['CSRF_COOKIE'] for storing the unmasked CSRF secret rather
than a masked version. This is an undocumented, private API.ModelAdmin.actions and
inlines attributes now default to an
empty tuple rather than an empty list to discourage unintended mutation.type="text/css" attribute is no longer included in <link> tags
for CSS form media.formset:added and formset:removed JavaScript events are now pure
JavaScript events and don't depend on jQuery. See
内联表单事件 for more details on the change.exc_info argument of the undocumented
django.utils.log.log_response() function is replaced by exception.size argument of the undocumented
django.views.static.was_modified_since() function is removed.POST requests.InlineAdminFormSet.non_form_errors property is replaced
by the non_form_errors() method. This is consistent with BaseFormSet.OPTIONS['loaders'] to override
this, if necessary.django.contrib.auth.views.SuccessURLAllowedHostsMixin
mixin is replaced by RedirectURLMixin.BaseConstraint subclasses must implement
validate() method to allow those
constraints to be used for validation.URLResolver._is_callback(),
URLResolver._callback_strs, and URLPattern.lookup_str() are
moved to django.contrib.admindocs.utils.Model.full_clean() method now converts an exclude value to a
set. It’s also preferable to pass an exclude value as a set to
the Model.clean_fields(), Model.full_clean(),
Model.validate_unique(), and Model.validate_constraints()
methods.asgiref is increased from 3.4.1 to
3.5.2.output_field when argument types match. As a consequence, resolving an
output_field for database functions and combined expressions may now
crash with mixed types. You will need to explicitly set the output_field
in such cases.makemessages command no longer changes .po files when up
to date. In older versions, POT-Creation-Date was always updated.Logging out via GET requests to the built-in logout view is deprecated. Use POST requests
instead.
If you want to retain the user experience of an HTML link, you can use a form that is styled to appear as a link:
<form id="logout-form" method="post" action="{% url 'admin:logout' %}">
{% csrf_token %}
<button type="submit">{% translate "Log out" %}</button>
</form>
#logout-form {
display: inline;
}
#logout-form button {
background: none;
border: none;
cursor: pointer;
padding: 0;
text-decoration: underline;
}
The context for sitemap index templates of a flat list of URLs is deprecated.
Custom sitemap index templates should be updated for the adjusted
context variables, expecting a list
of objects with location and optional lastmod attributes.
CSRF_COOKIE_MASKED transitional setting is deprecated.
The name argument of django.utils.functional.cached_property() is
deprecated as it's unnecessary as of Python 3.6.
The opclasses argument of
django.contrib.postgres.constraints.ExclusionConstraint is deprecated in
favor of using OpClass()
in ExclusionConstraint.expressions. To use it, you need to add
'django.contrib.postgres' in your INSTALLED_APPS.
After making this change, makemigrations will generate a new
migration with two operations: RemoveConstraint and AddConstraint.
Since this change has no effect on the database schema,
the SeparateDatabaseAndState
operation can be used to only update the migration state without running any
SQL. Move the generated operations into the state_operations argument of
SeparateDatabaseAndState. For
example:
class Migration(migrations.Migration):
...
operations = [
migrations.SeparateDatabaseAndState(
database_operations=[],
state_operations=[
migrations.RemoveConstraint(...),
migrations.AddConstraint(...),
],
),
]
The undocumented ability to pass errors=None to
SimpleTestCase.assertFormError() and
assertFormsetError()
is deprecated. Use errors=[] instead.
django.contrib.sessions.serializers.PickleSerializer is deprecated due to
the risk of remote code execution.
The usage of QuerySet.iterator() on a queryset that prefetches related
objects without providing the chunk_size argument is deprecated. In older
versions, no prefetching was done. Providing a value for chunk_size
signifies that the additional query per chunk needed to prefetch is desired.
Passing unsaved model instances to related filters is deprecated. In Django 5.0, the exception will be raised.
created=True is added to the signature of
RemoteUserBackend.configure_user(). Support for RemoteUserBackend
subclasses that do not accept this argument is deprecated.
The django.utils.timezone.utc alias to datetime.timezone.utc
is deprecated. Use datetime.timezone.utc directly.
Passing a response object and a form/formset name to
SimpleTestCase.assertFormError() and assertFormsetError() is
deprecated. Use:
assertFormError(response.context["form_name"], ...)
assertFormsetError(response.context["formset_name"], ...)
or pass the form/formset object directly instead.
The undocumented django.contrib.gis.admin.OpenLayersWidget is deprecated.
django.contrib.auth.hashers.CryptPasswordHasher is deprecated.
The ability to pass nulls_first=False or nulls_last=False to
Expression.asc() and Expression.desc() methods, and the OrderBy
expression is deprecated. Use None instead.
The "django/forms/default.html" and
"django/forms/formsets/default.html" templates which are a proxy to the
table-based templates are deprecated. Use the specific template instead.
The undocumented LogoutView.get_next_page() method is renamed to
get_success_url().
These features have reached the end of their deprecation cycle and are removed in Django 4.1.
See 在 3.2 中被废弃的功能 for details on these changes, including how to remove usage of these features.
copy.deepcopy() to class attributes in TestCase.setUpTestData() is
removed.BaseCommand.requires_system_checks is removed.whitelist argument and domain_whitelist attribute of
django.core.validators.EmailValidator are removed.default_app_config application configuration variable is removed.TransactionTestCase.assertQuerysetEqual() no longer calls repr() on a
queryset when compared to string values.django.core.cache.backends.memcached.MemcachedCache backend is
removed.django.contrib.messages.storage.cookie.CookieStorage is removed.5月 12, 2023