Django 5.2 release notes - UNDER DEVELOPMENT¶
Expected April 2025
Welcome to Django 5.2!
These release notes cover the new features, as well as some backwards incompatible changes you should be aware of when upgrading from Django 5.1 or earlier. We’ve begun the deprecation process for some features.
See the How to upgrade Django to a newer version guide if you’re updating an existing project.
Django 5.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 4.2, will end in April 2026.
Python compatibility¶
Django 5.2 supports Python 3.10, 3.11, 3.12, and 3.13. We highly recommend and only officially support the latest release of each series.
What’s new in Django 5.2¶
Automatic models import in the shell
¶
The shell
management command now automatically imports models from
all installed apps. You can view further details of the imported objects by
setting the --verbosity
flag to 2 or more:
$ python -Wall manage.py shell --verbosity=2
6 objects imported automatically, including:
from django.contrib.admin.models import LogEntry
from django.contrib.auth.models import Group, Permission, User
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
...\> py -Wall manage.py shell --verbosity=2
6 objects imported automatically, including:
from django.contrib.admin.models import LogEntry
from django.contrib.auth.models import Group, Permission, User
from django.contrib.contenttypes.models import ContentType
from django.contrib.sessions.models import Session
This behavior can be customized to add or remove automatic imports.
Composite Primary Keys¶
The new django.db.models.CompositePrimaryKey
allows tables to be
created with a primary key consisting of multiple fields.
To use a composite primary key, when defining a model set the pk
attribute
to be a CompositePrimaryKey
:
from django.db import models
class Release(models.Model):
pk = models.CompositePrimaryKey("version", "name")
version = models.IntegerField()
name = models.CharField(max_length=20)
See Composite primary keys for more details.
Simplified override of BoundField
¶
Prior to version 5.2, overriding Field.get_bound_field()
was the only
option to use a custom BoundField
. Django now supports
specifying the following attributes to customize form rendering:
BaseRenderer.bound_field_class
at the project level,Form.bound_field_class
at the form level, andField.bound_field_class
at the field level.
For example, to customize the BoundField
of a Form
class:
from django import forms
class CustomBoundField(forms.BoundField):
custom_class = "custom"
def css_classes(self, extra_classes=None):
result = super().css_classes(extra_classes)
if self.custom_class not in result:
result += f" {self.custom_class}"
return result.strip()
class CustomForm(forms.Form):
bound_field_class = CustomBoundField
name = forms.CharField(
label="Your Name",
max_length=100,
required=False,
widget=forms.TextInput(attrs={"class": "name-input-class"}),
)
email = forms.EmailField(label="Your Email")
When rendering a CustomForm
instance, the following HTML is included:
<div class="custom">
<label for="id_name">Your Name:</label>
<input type="text" name="name" class="name-input-class" maxlength="100" id="id_name">
</div>
<div class="custom">
<label for="id_email">Your Email:</label>
<input type="email" name="email" maxlength="320" required="" id="id_email">
</div>
See Customizing BoundField for more details about this feature.
Minor features¶
django.contrib.admin
¶
django.contrib.admindocs
¶
Links to components in docstrings now supports custom link text, using the format
:role:`link text <link>`
. See documentation helpers for more details.The model pages are now restricted to users with the corresponding view or change permissions.
django.contrib.auth
¶
The default iteration count for the PBKDF2 password hasher is increased from 870,000 to 1,000,000.
The following new asynchronous methods are now provided, using an
a
prefix:Auth backends can now provide async implementations which are used when calling async auth functions (e.g.
aauthenticate()
) to reduce context-switching which improves performance. See adding an async interface for more details.The password validator classes now have a new method
get_error_message()
, which can be overridden in subclasses to customize the error messages.
django.contrib.gis
¶
GDAL now supports curved geometries
CurvePolygon
,CompoundCurve
,CircularString
,MultiSurface
, andMultiCurve
via the newOGRGeometry.has_curve
property, and theOGRGeometry.get_linear_geometry()
andOGRGeometry.get_curve_geometry()
methods.coveredby
andisvalid
lookups,Collect
aggregation, andGeoHash
andIsValid
database functions are now supported on MariaDB 11.7+.
Database backends¶
MySQL connections now default to using the
utf8mb4
character set, instead ofutf8
, which is an alias for the deprecated character setutf8mb3
.Oracle backends now support connection pools, by setting
"pool"
in theOPTIONS
part of your database configuration.
Decorators¶
method_decorator()
now supports wrapping asynchronous view methods.
Email¶
Tuple items of
EmailMessage.attachments
andEmailMultiAlternatives.attachments
are now named tuples, as opposed to regular tuples.EmailMultiAlternatives.alternatives
is now a list of named tuples, as opposed to regular tuples.The new
body_contains()
method returns a boolean indicating whether a provided text is contained in the emailbody
and in all attached MIME typetext/*
alternatives.
Error Reporting¶
The attribute
SafeExceptionReporterFilter.hidden_settings
now treats values as sensitive if their name includesAUTH
.
Forms¶
The new
ColorInput
form widget is for entering a color inrrggbb
hexadecimal format and renders as<input type="color" ...>
. Some browsers support a visual color picker interface for this input type.The new
SearchInput
form widget is for entering search queries and renders as<input type="search" ...>
.The new
TelInput
form widget is for entering telephone numbers and renders as<input type="tel" ...>
.The new
field_id
argument forErrorList
allows an HTMLid
attribute to be added in the error template. SeeErrorList.field_id
for details.An
aria_describedby
property is added toBoundField
to ease use of this HTML attribute in templates.To improve accessibility for screen reader users
aria-describedby
is used to associate form fields with their error messages. See how form errors are displayed for details.The new asset object
Script
is available for adding custom HTML-attributes to JavaScript in form media. See paths as objects for more details.
Management Commands¶
A new warning is displayed when running
runserver
, indicating that it is unsuitable for production. This warning can be suppressed by setting theHIDE_PRODUCTION_WARNING
environment variable to"true"
.The
makemigrations
andmigrate
commands have a newCommand.autodetector
attribute for subclasses to override in order to use a custom autodetector class.The new
BaseCommand.get_check_kwargs()
method can be overridden in custom commands to control the running of system checks, e.g. to opt into database-dependent checks.
Migrations¶
The new operation
AlterConstraint
is a no-op operation that alters constraints without dropping and recreating constraints in the database.
Models¶
The
SELECT
clause generated when usingQuerySet.values()
andQuerySet.values_list()
now matches the specified order of the referenced expressions. Previously, the order was based on a set of counterintuitive rules which made query combination through methods such asQuerySet.union()
unpredictable.Added support for validation of model constraints which use a
GeneratedField
.The new
Expression.set_returning
attribute specifies that the expression contains a set-returning function, enforcing subquery evaluation. This is necessary for many Postgres set-returning functions.CharField.max_length
is no longer required to be set on SQLite, which supports unlimitedVARCHAR
columns.QuerySet.explain()
now supports thememory
andserialize
options on PostgreSQL 17+.The new
JSONArray
database function accepts a list of field names or expressions and returns a JSON array containing those values.The new
Expression.allows_composite_expressions
attribute specifies that the expression allows composite expressions, for example, to support composite primary keys.
Requests and Responses¶
The new
HttpResponse.text
property provides the string representation ofHttpResponse.content
.The new
HttpRequest.get_preferred_type()
method can be used to query the preferred media type the client accepts.The new
preserve_request
argument forHttpResponseRedirect
andHttpResponsePermanentRedirect
determines whether the HTTP status codes 302/307 or 301/308 are used, respectively.The new
preserve_request
argument forredirect()
allows to instruct the user agent to reuse the HTTP method and body during redirection using specific status codes.
Serialization¶
Each serialization format now defines a
Deserializer
class, rather than a function, to improve extensibility when defining a custom serialization format.
Templates¶
The new
simple_block_tag()
decorator enables the creation of simple block tags, which can accept and use a section of the template.
Tests¶
Stack frames from Django’s custom assertions are now hidden. This makes test failures easier to read and enables
test --pdb
to directly enter into the failing test method.Data loaded from
fixtures
and from migrations enabled with serialized_rollback=True are now available duringTransactionTestCase.setUpClass()
.
URLs¶
reverse()
now acceptsquery
andfragment
keyword arguments, allowing the addition of a query string and/or fragment identifier in the generated URL, respectively.
Utilities¶
SafeString
now returnsNotImplemented
in__add__
for non-string right-hand side values. This aligns with thestr
addition behavior and allows__radd__
to be used if available.format_html_join()
now supports taking an iterable of mappings, passing their contents as keyword arguments toformat_html()
.
Backwards incompatible changes in 5.2¶
Database backend API¶
This section describes changes that may be needed in third-party database backends.
The new
Model._is_pk_set()
method allows checking if a Model instance’s primary key is defined.BaseDatabaseOperations.adapt_decimalfield_value()
is now a no-op, simply returning the given value.
django.contrib.gis
¶
Support for PostGIS 3.0 is removed.
Support for GDAL 3.0 is removed.
Dropped support for PostgreSQL 13¶
Upstream support for PostgreSQL 13 ends in November 2025. Django 5.2 supports PostgreSQL 14 and higher.
Changed MySQL connection character set default¶
MySQL connections now default to using the utf8mb4
character set, instead
of utf8
, which is an alias for the deprecated character set utf8mb3
.
utf8mb3
can be specified in the OPTIONS
part of the DATABASES
setting, if needed for legacy databases.
Miscellaneous¶
Adding
EmailMultiAlternatives.alternatives
is now only supported via theattach_alternative()
method.The minimum supported version of
gettext
is increased from 0.15 to 0.19.HttpRequest.accepted_types
is now sorted by the client’s preference, based on the request’sAccept
header.The attributes
UniqueConstraint.violation_error_code
andUniqueConstraint.violation_error_message
are now always used when provided. Previously, they were ignored ifUniqueConstraint.fields
was set without aUniqueConstraint.condition
.The
debug()
context processor is no longer included in the default project template.The following methods now have
alters_data=True
set to prevent side effects when rendering a template context:The minimum supported version of
oracledb
is increased from 1.3.2 to 2.3.0.Built-in aggregate functions accepting only one argument (
Avg
,Count
,Max
,Min
,StdDev
,Sum
, andVariance
) now raiseTypeError
when called with an incorrect number of arguments.
Features deprecated in 5.2¶
Miscellaneous¶
The
all
argument for thedjango.contrib.staticfiles.finders.find()
function is deprecated in favor of thefind_all
argument.The fallback to
request.user
whenuser
isNone
indjango.contrib.auth.login()
anddjango.contrib.auth.alogin()
will be removed.The
ordering
keyword argument of the PostgreSQL specific aggregation functionsdjango.contrib.postgres.aggregates.ArrayAgg
,django.contrib.postgres.aggregates.JSONBAgg
, anddjango.contrib.postgres.aggregates.StringAgg
is deprecated in favor of theorder_by
argument.