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.
See the Jak zaktualizować Django do nowszej wersji guide if you’re updating an existing project.
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
Window functions 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.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.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
Nadpisywanie predefiniowanych metod modelu 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 Aggregation functions
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.
sie 06, 2024