April 3, 2023
Welcome to Django 4.2!
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.1 or earlier. We've begun the deprecation process for some features.
如果你要更新现有的项目,请看 如何将 Django 更新至新的版本 指南。
Django 4.2 is designated as a 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.
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.
Django now supports psycopg version 3.1.8 or higher. To update your code,
install the psycopg library, you don't need to change the
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.
The new Field.db_comment
and
Meta.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 AlterModelTableComment
operation allows changing table comments defined in the
Meta.db_table_comment
.
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.
The new django.core.files.storage.InMemoryStorage
class provides a
non-persistent storage useful for speeding up tests by avoiding disk access.
The new STORAGES
setting allows configuring multiple custom file
storage backends. It also controls storage engines for managing
files (the "default"
key) and static files (the "staticfiles"
key).
The old DEFAULT_FILE_STORAGE
and STATICFILES_STORAGE
settings are
deprecated as of this release.
django.contrib.admin
¶filter_horizontal
and
filter_vertical
widgets are now
filterable.admin/base.html
template now has a new block nav-breadcrumbs
which contains the navigation landmark and the breadcrumbs
block.ModelAdmin.list_editable
now uses atomic transactions when making
edits.django.contrib.auth
¶UserCreationForm
now saves many-to-many
form fields for a custom user model.BaseUserCreationForm
is now the
recommended base class for customizing the user creation form.django.contrib.gis
¶id
key for serialized features, which defaults to the primary key of
objects.GDALRaster
class now supports
pathlib.Path
.GeoIP2
class now supports .mmdb
files downloaded from DB-IP.map_css
block) to better comply with a strict Content
Security Policy.OpenLayersWidget
is now based on
OpenLayers 7.2.2 (previously 4.6.5).isempty
lookup and
IsEmpty()
expression allow filtering empty geometries on PostGIS.FromWKB()
and FromWKT()
functions allow creating geometries from Well-known binary (WKB) and
Well-known text (WKT) representations.django.contrib.postgres
¶trigram_strict_word_similar
lookup, and the
TrigramStrictWordSimilarity()
and
TrigramStrictWordDistance()
expressions allow
using trigram strict word similarity.arrayfield.overlap
lookup now supports QuerySet.values()
and values_list()
as a right-hand side.django.contrib.sitemaps
¶Sitemap.get_languages_for_item()
method allows customizing the
list of languages for which the item is displayed.django.contrib.staticfiles
¶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
.ManifestStaticFilesStorage.manifest_hash
attribute provides
a hash over all files in the manifest and changes whenever one of the files
changes."assume_role"
option is now supported in OPTIONS
on
PostgreSQL to allow specifying the session role."server_side_binding"
option is now supported in
OPTIONS
on PostgreSQL with psycopg
3.1.8+ to allow using
server-side binding cursors.**********
) in error reports.ModelForm
now accepts the new Meta
option
formfield_callback
to customize form fields.modelform_factory()
now respects the
formfield_callback
attribute of the form
’s Meta
.BEGIN
, COMMIT
, and ROLLBACK
) at the DEBUG
level.makemessages
command now supports locales with private sub-tags
such as nl_NL-x-informal
.makemigrations --update
option merges model changes into
the latest migration and optimizes the resulting operations.enum.Flag
objects.QuerySet
now extensively supports filtering against
窗口函数 with the exception of disjunctive filter lookups
against window functions when performing aggregation.prefetch_related()
now supports
Prefetch
objects with sliced querysets.Field
instances is now supported.robust
argument for on_commit()
allows performing actions that can fail after a database transaction is
successfully committed.KT()
expression represents
the text value of a key, index, or path transform of
JSONField
.Now
now supports microsecond precision
on MySQL and millisecond precision on SQLite.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: adelete()
,
arefresh_from_db()
, and asave()
.a
prefix: aadd()
,
aclear()
, aremove()
, and
aset()
.CharField.max_length
is no
longer required to be set on PostgreSQL, which supports unlimited VARCHAR
columns.StreamingHttpResponse
now supports async iterators
when Django is served via ASGI.The test --debug-sql
option now formats SQL queries with
sqlparse
.
The RequestFactory
,
AsyncRequestFactory
, Client
, and
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.
# 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"})
encoder
parameter for django.utils.html.json_script()
function allows customizing a JSON encoder class.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.django.utils.http.content_disposition_header()
function returns
a Content-Disposition
HTTP header value as specified by RFC 6266.CommonPasswordValidator
is updated
to the most recent version.本节介绍了第三方数据库后端可能需要的更改。
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.inspectdb
now uses display_size
from
DatabaseIntrospection.get_table_description()
rather than
internal_size
for CharField
.Upstream support for MariaDB 10.3 ends in May 2023. Django 4.2 supports MariaDB 10.4 and higher.
Upstream support for MySQL 5.7 ends in October 2023. Django 4.2 supports MySQL 8 and higher.
Upstream support for PostgreSQL 11 ends in November 2023. Django 4.2 supports PostgreSQL 12 and higher.
update_fields
in Model.save()
may now be required¶In order to avoid updating unnecessary columns,
QuerySet.update_or_create()
now passes update_fields
to the
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
重写之前定义的模型方法 for more details.
MySQL 8+ allows functional dependencies on GROUP BY
columns, so the
pre-Django 4.2 workaround of grouping by primary keys of the main table is
removed. As a consequence, using RawSQL()
aggregations is no longer
supported on MySQL as there is no way to determine if such aggregations are
needed or valid in the GROUP BY
clause. Use 聚合函数
instead.
django.http.multipartparser.parse_header()
function is
removed. Use django.utils.http.parse_header_parameters()
instead.{% blocktranslate asvar … %}
result is now marked as
safe for (HTML) output purposes.autofocus
HTML attribute in the admin search box is removed as it can
be confusing for screen readers.makemigrations --check
option no longer creates missing
migration files.alias
argument for Expression.get_group_by_cols()
is removed.sqlparse
is increased from 0.2.2 to
0.3.1.negated
parameter of the
Exists
expression is removed.is_summary
argument of the undocumented Query.add_annotation()
method is removed.asgiref
is increased from 3.5.2 to
3.6.0.UserCreationForm
now rejects usernames
that differ only in case. If you need the previous behavior, use
BaseUserCreationForm
instead.mysqlclient
is increased from 1.4.0 to
1.4.3.argon2-cffi
is increased from 19.1.0 to
19.2.0.Pillow
is increased from 6.2.0 to 6.2.1.jinja2
is increased from 2.9.2 to
2.11.0.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.PROJ
< 5 is removed.EmailBackend
now verifies a
hostname
and
certificates
. If you need the
previous behavior that is less restrictive and not recommended, subclass
EmailBackend
and override the ssl_context
property.index_together
option is deprecated in favor of indexes
¶The Meta.index_together
option is deprecated in favor of the 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 makemigrations
command will generate a migration
containing a 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
AddIndex
and
RemoveIndex
operations instead.
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.
The BaseUserManager.make_random_password()
method is deprecated. See
recipes and best practices
for using Python's secrets
module to generate passwords.
The length_is
template filter is deprecated in favor of length
and the ==
operator within an {% if %}
tag. For example
{% if value|length == 4 %}…{% endif %}
{% if value|length == 4 %}True{% else %}False{% endif %}
instead of:
{% 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.
12月 05, 2023