Django new version releasedDjango 4.2 Release Notes

Django 4.2 release notes?
April 3, 2023

Welcome to Django 4.2!

These release notes cover new features, as well as some backwards-incompatible changes you need to be aware of when upgrading from Django 4.1 or earlier. We have already started the deprecation process for some features.

If you’re updating an existing project, see the How to Upgrade Django to a Newer Version guide.

Django 4.2 is designated as a long-term support release. It will receive security updates for at least three years after 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, and 3.11. We strongly recommend and only officially support the latest version of each series.

What’s new in Django 4.2?
Psycopg 3 support?
Django now supports psycopg 3.1.8 or later. To update your code, install the psycopg library, you don’t need to change ENGINE because django.db.backends.postgresql it supports both libraries.

Support for psycopg2 may be deprecated and removed at some point in the future.

Note that psycopg3 introduces some breaking changes over psycopg2 .x. Therefore, you may need to make some changes to account for differences with psycopg2.

Comments on columns and tables?
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"

Additionally, a new AlterModelTableComment operation allows altering Meta.db_table_comment.

Mitigation for BREACH attack?
GZipMiddleware now includes mitigations for BREACH attacks. It will add up to 100 random bytes to the gzip response, making BREACH attacks more difficult. Read more about mitigation techniques in the Heal The Breach (HTB) paper.

Memory file storage?
The new django.core.files.storage.InMemoryStorage class provides a non-persistent storage that speeds up testing by avoiding disk access.

Custom file storage?
The new STORAGES setting allows configuring multiple custom file storage backends. It also controls the storage engine used to manage files (“default” key) and static files (“staticfiles” key).

Starting with this release, the old DEFAULT_FILE_STORAGE and settings are deprecated. STATICFILES_STORAGE

Secondary function?
django.contrib.admin?
A light or dark theme for admins can now be toggled in the UI, or set to follow system settings.
The admin’s font stack now prefers system UI fonts, no longer needing to download fonts. Additionally, CSS variables can be used to more easily override the default font family.
The admin/delete_confirmation.html template now has some extra blocks and script hooks to ease customization.
The selection options for filter_horizontal and filter_vertical widgets are now filterable.
The admin/base.html template now has a new block nav-breadcrumbs which contains the navigation landmarks and breadcrumbs blocks.
ModelAdmin.list_editable now uses atomic transactions when making edits.
jQuery was upgraded from version 3.6.0 to 3.6.4.
django.contrib.auth?
The default iteration count for the PBKDF2 password hasher was increased from 390,000 to 600,000.
UserCreationForm now holds many-to-many form fields for custom User models.
The new BaseUserCreationForm is now the recommended base class for custom user creation forms.
django.contrib.gis?
The GeoJSON serializer now outputs the id key of the serialized feature, which defaults to the object’s primary key.
The class GDALRaster now supports pathlib.Path.
The class GeoIP2 now supports .mmdb files downloaded from DB-IP.
OpenLayers template widgets no longer contain inline CSS (this also removes the previous map_css block) to better comply with strict content security policies.
OpenLayersWidget is now based on OpenLayers 7.2.2 (previously 4.6.5).
New isempty lookup and IsEmpty() expression allow filtering empty geometries on PostGIS.
The new FromWKB() and FromWKT() functions allow creation of geometries from Well-known binary (WKB) and Well-known text (WKT) representations.
django.contrib.postgres?
The new trigram_strict_word_similar lookup and expression allow trigram strict word similarity using TrigramStrictWordSimilarity() . TrigramStrictWordDistance()
Lookup arrayfield.overlap now supports QuerySet.values() and values_list() as the right side.
django.contrib.sitemaps?
The new Sitemap.get_languages_for_item() method allows customizing the list of languages for which an item is displayed.
django.contrib.staticfiles?
ManifestStaticFilesStorage now experimentally supports replacing JavaScript module path imports and statements with hash-corresponding statements. export If you want to try it out, subclass ManifestStaticFilesStorage and set the support_js_module_import_aggregation property to True.
The new ManifestStaticFilesStorage.manifest_hash property provides a hash of all files in the manifest and changes when one of the files changes.
database backend?
PostgreSQL”assume_role” now supports new options to allow specifying session roles. OPTIONS
PostgreSQL 3.1.8 + “server_side_binding” now supports a new option to allow the use of server-side bound cursors. OPTIONSpsycopg
error report?
The debug page now shows exception descriptions and fine-grained error locations on Python 3.11+.
Session cookies are now considered credentials, so *********** is hidden and replaced with asterisks ( ) in bug reports.
sheet?
ModelForm now accepts a new Meta option for custom form fields. formfield_callback
modelform_factory() now respects the form attribute Meta of formfield_callback.
globalization?
Added support and translation for Central Kurdish (Sorani) language.
Record?
The django.db.backends logger now logs transaction management queries (BEGIN, COMMIT, and ROLLBACK) at the DEBUG level.
Management command?
The makemessages command now supports locales with private subtags, such as nl_NL-x-informal.
New option to merge model changes into latest migration and optimize generated operations. makemigrations –update
migrate?
Migration now supports serialization of enum.Flag objects.
Model?
QuerySet now broadly supports filtering on Window functions, with the exception of disjunctive filter lookups on window functions when performing aggregations.
prefetch_related() now supports Prefetching objects with sliced querysets.
Field now supports registering lookups on instances.
A new robust parameter to on_commit() allows operations that might fail after a database transaction has been successfully committed.
The new KT() expression represents the key, index, or path of the converted text value of the JSONField.
Now supports microsecond precision for MySQL and millisecond precision for SQLite.
F()BooleanField can now negate output expressions using ~F() (the inversion operator).
Model now provides asynchronous versions of some methods that work with the database, prefixed with a: adelete(), arefresh_from_db(), and asave().
Dependency managers now provide asynchronous versions of methods to change a set of related objects, using a prefix: aadd() , aclear() , remove() , and aset() .
CharField.max_length no longer needs to be set on PostgreSQL which supports unlimited VARCHAR columns.
request and response?
StreamingHttpResponse now supports asynchronous iterators when Django is serving it via ASGI.
test?
This option now uses .test –debug-sqlsqlparse

The , , and classes now support parameters that accept the header name RequestFactory and a dictionary of values. This allows a more natural syntax for declaring headers. AsyncRequestFactoryClientAsyncClientheaders

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?
A new argument to the encoder function of django.utils.html.json_script() allows custom JSON encoder classes.
Private internal sales copies of urllib.parse.urlsplit() now strips ‘\r’, ‘\\
‘, and ‘\t’ (see CVE-2022-0391 and bpo-43882). This is to protect projects that may mistakenly use the internal url_has_allowed_host_and_scheme() function instead of one of the documented functions to handle URL redirection. Django functions are not affected.
The new django.utils.http.content_disposition_header() function returns the Content-Disposition HTTP header value specified by RFC 6266.
Validator?
The common password list CommonPasswordValidator used has been updated to the latest version.
Backwards incompatible changes in 4.2?
Database backend API ?
This section describes changes that may be required for third-party database backends.

DatabaseFeatures.allows_group_by_pk was removed because it was only kept to accommodate the MySQL extension, which was superseded by proper feature dependency detection in MySQL 5.7.15. Note that it is still supported and should be enabled if your backend supports feature dependency detection in the clause DatabaseFeatures.allows_group_by_selected_pks specified by the standard. GROUP BYSQL:1999
inspectdb now uses display_sizefrom DatabaseIntrospection.get_table_description() instead of internal_sizefor CharField.
Drop support for MariaDB 10.3?
Upstream support for MariaDB 10.3 will end in May 2023. Django 4.2 supports MariaDB 10.4 and later.

MySQL 5.7 is no longer supported ?
Upstream support for MySQL 5.7 will end in October 2023. Django 4.2 supports MySQL 8 and later.

Drop support for PostgreSQL 11?
Upstream support for PostgreSQL 11 will end in November 2023. Django 4.2 supports PostgreSQL 12 and later.

update_fields now Model.save() may need to set?
To avoid updating unnecessary columns, QuerySet.update_or_create() now passes update_fields to the Model.save() call. Therefore, any fields that are modified in custom methods should be added to the save() keyword arguments before calling save(). See Overriding Predefined Model Methods for more details. update_fieldssuper()

Miscellaneous?
The undocumented django.http.multipartparser.parse_header() function has been removed. Use django.utils.http.parse_header_parameters() instead.
{% blocktranslate asvar … %} results are now marked safe for (HTML) output purposes.
The HTML attribute in the autofocus admin search box has been removed as it could confuse screen readers.
This option no longer creates missing migration files. makemigrations –check
The aliasfor argument has been removed for Expression.get_group_by_cols().
Minimum supported version of sqlparse increased from 0.2.2 to 0.3.1.
The undocumented parameter Exists for negated expressions has been removed.
The is_summary parameter of the undocumented method was removed by Query.add_annotation().
The minimum supported version of SQLite has been increased from 3.9.0 to 3.21.0.
Minimum supported version of asgiref 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.
Minimum supported version of mysqlclient increased from 1.4.0 to 1.4.3.
Minimum supported version of argon2-cffi increased from 19.1.0 to 19.2.0.
Minimum supported version of Pillow increased from 6.2.0 to 6.2.1.
Minimum supported version of jinja2 increased from 2.9.2 to 2.11.0.
Minimum supported version of redis-py increased from 3.0.0 to 3.4.0.
A file-like object wsgi.input must be provided for manually instantiated WSGIRequest objects. Previously, Django was more permissive than the expected behavior specified by the WSGI specification.
PROJ removed support for < 5 .
EmailBackend now verifies a hostname and certificates. If you need the less restrictive and deprecated previous behavior, subclass EmailBackend and override the ssl_context property.
Features deprecated in 4.2?
index_together is not recommended to use 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 that includes a RenameIndex operation that will rename an existing index.

The migration AlterIndexTogether action is now only officially supported for pre-Django 4.2 migration files. It is still part of the public API for backwards compatibility reasons, and there are no plans to deprecate or remove it, but it should not be used for new migrations. Use AddIndex and RemoveIndex operations instead.

Passing encoded JSON string literal JSONField to ?
JSONField and its associated lookups and aggregations are used to allow JSON-encoded string literals to be passed, which leads to ambiguity as to whether a string literal is already encoded from the perspective of the database backend.

During the deprecation, JSON decoding of string literals will be attempted and, on success, a warning is issued that a non-encoded form is passed.

Code for passing 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=[]),
)
Starting with Django 5.1+, string literals are implicitly interpreted as JSON string literals.

Miscellaneous?
The BaseUserManager.make_random_password() method is deprecated. Check out the recipes and best practices for generating passwords using Python modules. secrets

The template length_is filter is deprecated in favor of the length and operator in tags. For example =={% if %}

{% if value|length == 4 %}…{% endif %}
{% if value|length == 4 %}True{% else %}False{% endif %}
replace:

{% 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 Deprecated CharField(db_collation=”…”) case-insensitive non-deterministic collation.

django.contrib.postgres.fields.CIEmailField deprecated EmailField(db_collation=”…”) case-insensitive non-deterministic collation.

django.contrib.postgres.fields.CITextField Deprecated TextField(db_collation=”…”) case-insensitive non-deterministic collation.

django.contrib.postgres.fields.CITextmixin is deprecated.

The map_height and map_width properties of BaseGeometryWidget are deprecated, use CSS instead to resize the map widget.

SimpleTestCase.assertFormsetError() is deprecated in favor of assertFormSetError().

TransactionTestCase.assertQuerysetEqual() is deprecated in favor of assertQuerySetEqual().

Passing positional arguments to SignerandTimestampSigner 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.