{"title":"Django 5.2 release notes","version":"dev","locale":"en","docname":"releases/5.2","url":"/en/dev/releases/5.2/","canonical":"https://djangodocs.dev/en/dev/releases/5.2/","summary":"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…","html":"<h1>Django 5.2 release notes<a class=\"heading-anchor\" href=\"#django-5-2-release-notes\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p><em>April 2, 2025</em></p>\n<p>Welcome to Django 5.2!</p>\n<p>These release notes cover the <a class=\"reference internal\" href=\"#whats-new-5-2\"><span class=\"std std-ref\">new features</span></a>, as well as\nsome <a class=\"reference internal\" href=\"#backwards-incompatible-5-2\"><span class=\"std std-ref\">backwards incompatible changes</span></a> you\nshould be aware of when upgrading from Django 5.1 or earlier. We’ve\n<a class=\"reference internal\" href=\"#deprecated-features-5-2\"><span class=\"std std-ref\">begun the deprecation process for some features</span></a>.</p>\n<p>See the <a class=\"reference internal\" href=\"/en/dev/howto/upgrade-version/\"><span class=\"doc\">How to upgrade Django to a newer version</span></a> guide if you’re updating an existing\nproject.</p>\n<p>Django 5.2 is designated as a <a class=\"reference internal\" href=\"/en/dev/internals/release-process/#term-Long-term-support-release\"><span class=\"xref std std-term\">long-term support release</span></a>. It will receive security updates for at least\nthree years after its release. Support for the previous LTS, Django 4.2, will\nend in April 2026.</p>\n<section id=\"python-compatibility\">\n<h2>Python compatibility<a class=\"heading-anchor\" href=\"#python-compatibility\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Django 5.2 supports Python 3.10, 3.11, 3.12, 3.13, and 3.14 (as of 5.2.8). We\n<strong>highly recommend</strong> and only officially support the latest release of each\nseries.</p>\n</section>\n<section id=\"what-s-new-in-django-5-2\">\n<span id=\"whats-new-5-2\"></span><h2>What’s new in Django 5.2<a class=\"heading-anchor\" href=\"#what-s-new-in-django-5-2\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"automatic-models-import-in-the-shell\">\n<h3>Automatic models import in the <code class=\"docutils literal notranslate\">shell</code><a class=\"heading-anchor\" href=\"#automatic-models-import-in-the-shell\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>The <a class=\"reference internal\" href=\"/en/dev/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\">shell</code></a> management command now automatically imports models from\nall installed apps. You can view further details of the imported objects by\nsetting the <code class=\"docutils literal notranslate\">--verbosity</code> flag to 2 or more:</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-0-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code><span class=\"gp\">$ </span>python -Wall manage.py shell --verbosity<span class=\"o\">=</span><span class=\"m\">2</span>\n<span class=\"go\">6 objects imported automatically, including:</span>\n\n<span class=\"go\">  from django.contrib.admin.models import LogEntry</span>\n<span class=\"go\">  from django.contrib.auth.models import Group, Permission, User</span>\n<span class=\"go\">  from django.contrib.contenttypes.models import ContentType</span>\n<span class=\"go\">  from django.contrib.sessions.models import Session</span>\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-0-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> py -Wall manage.py shell --verbosity=2\n<span class=\"go\">6 objects imported automatically, including:</span>\n\n<span class=\"go\">  from django.contrib.admin.models import LogEntry</span>\n<span class=\"go\">  from django.contrib.auth.models import Group, Permission, User</span>\n<span class=\"go\">  from django.contrib.contenttypes.models import ContentType</span>\n<span class=\"go\">  from django.contrib.sessions.models import Session</span>\n</code></pre></div></div></div>\n<p>This <a class=\"reference internal\" href=\"/en/dev/howto/custom-shell/#customizing-shell-auto-imports\"><span class=\"std std-ref\">behavior can be customized</span></a> to add\nor remove automatic imports.</p>\n</section>\n<section id=\"composite-primary-keys\">\n<h3>Composite Primary Keys<a class=\"heading-anchor\" href=\"#composite-primary-keys\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>The new <a class=\"reference internal\" href=\"/en/dev/ref/models/fields/#django.db.models.CompositePrimaryKey\" title=\"django.db.models.CompositePrimaryKey\"><code class=\"xref py py-class docutils literal notranslate\">django.db.models.CompositePrimaryKey</code></a> allows tables to be\ncreated with a primary key consisting of multiple fields.</p>\n<p>To use a composite primary key, when defining a model set the <code class=\"docutils literal notranslate\">pk</code> attribute\nto be a <code class=\"docutils literal notranslate\">CompositePrimaryKey</code>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django.db</span> <span class=\"kn\">import</span> models\n\n\n<span class=\"k\">class</span> <span class=\"nc\">Release</span><span class=\"p\">(</span>models<span class=\"o\">.</span>Model<span class=\"p\">):</span>\n    pk <span class=\"o\">=</span> models<span class=\"o\">.</span>CompositePrimaryKey<span class=\"p\">(</span><span class=\"s2\">&quot;version&quot;</span><span class=\"p\">,</span> <span class=\"s2\">&quot;name&quot;</span><span class=\"p\">)</span>\n    version <span class=\"o\">=</span> models<span class=\"o\">.</span>IntegerField<span class=\"p\">()</span>\n    name <span class=\"o\">=</span> models<span class=\"o\">.</span>CharField<span class=\"p\">(</span>max_length<span class=\"o\">=</span><span class=\"mi\">20</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>See <a class=\"reference internal\" href=\"/en/dev/topics/composite-primary-key/\"><span class=\"doc\">Composite primary keys</span></a> for more details.</p>\n</section>\n<section id=\"simplified-override-of-boundfield\">\n<h3>Simplified override of <a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#django.forms.BoundField\" title=\"django.forms.BoundField\"><code class=\"xref py py-class docutils literal notranslate\">BoundField</code></a><a class=\"heading-anchor\" href=\"#simplified-override-of-boundfield\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Prior to version 5.2, overriding <a class=\"reference internal\" href=\"/en/dev/ref/forms/fields/#django.forms.Field.get_bound_field\" title=\"django.forms.Field.get_bound_field\"><code class=\"xref py py-meth docutils literal notranslate\">Field.get_bound_field()</code></a> was the only\noption to use a custom <a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#django.forms.BoundField\" title=\"django.forms.BoundField\"><code class=\"xref py py-class docutils literal notranslate\">BoundField</code></a>. Django now supports\nspecifying the following attributes to customize form rendering:</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/forms/renderers/#django.forms.renderers.BaseRenderer.bound_field_class\" title=\"django.forms.renderers.BaseRenderer.bound_field_class\"><code class=\"xref py py-attr docutils literal notranslate\">BaseRenderer.bound_field_class</code></a> at the project level,</p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#django.forms.Form.bound_field_class\" title=\"django.forms.Form.bound_field_class\"><code class=\"xref py py-attr docutils literal notranslate\">Form.bound_field_class</code></a> at the form level, and</p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/forms/fields/#django.forms.Field.bound_field_class\" title=\"django.forms.Field.bound_field_class\"><code class=\"xref py py-attr docutils literal notranslate\">Field.bound_field_class</code></a> at the field level.</p></li>\n</ul>\n<p>For example, to customize the <code class=\"docutils literal notranslate\">BoundField</code> of a <code class=\"docutils literal notranslate\">Form</code> class:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span> <span class=\"nn\">django</span> <span class=\"kn\">import</span> forms\n\n\n<span class=\"k\">class</span> <span class=\"nc\">CustomBoundField</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>BoundField<span class=\"p\">):</span>\n\n    custom_class <span class=\"o\">=</span> <span class=\"s2\">&quot;custom&quot;</span>\n\n    <span class=\"k\">def</span> <span class=\"nf\">css_classes</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">,</span> extra_classes<span class=\"o\">=</span><span class=\"kc\">None</span><span class=\"p\">):</span>\n        result <span class=\"o\">=</span> <span class=\"nb\">super</span><span class=\"p\">()</span><span class=\"o\">.</span>css_classes<span class=\"p\">(</span>extra_classes<span class=\"p\">)</span>\n        <span class=\"k\">if</span> <span class=\"bp\">self</span><span class=\"o\">.</span>custom_class <span class=\"ow\">not</span> <span class=\"ow\">in</span> result<span class=\"p\">:</span>\n            result <span class=\"o\">+=</span> <span class=\"sa\">f</span><span class=\"s2\">&quot; </span><span class=\"si\">{</span><span class=\"bp\">self</span><span class=\"o\">.</span>custom_class<span class=\"si\">}</span><span class=\"s2\">&quot;</span>\n        <span class=\"k\">return</span> result<span class=\"o\">.</span>strip<span class=\"p\">()</span>\n\n\n<span class=\"k\">class</span> <span class=\"nc\">CustomForm</span><span class=\"p\">(</span>forms<span class=\"o\">.</span>Form<span class=\"p\">):</span>\n    bound_field_class <span class=\"o\">=</span> CustomBoundField\n\n    name <span class=\"o\">=</span> forms<span class=\"o\">.</span>CharField<span class=\"p\">(</span>\n        label<span class=\"o\">=</span><span class=\"s2\">&quot;Your Name&quot;</span><span class=\"p\">,</span>\n        max_length<span class=\"o\">=</span><span class=\"mi\">100</span><span class=\"p\">,</span>\n        required<span class=\"o\">=</span><span class=\"kc\">False</span><span class=\"p\">,</span>\n        widget<span class=\"o\">=</span>forms<span class=\"o\">.</span>TextInput<span class=\"p\">(</span>attrs<span class=\"o\">=</span><span class=\"p\">{</span><span class=\"s2\">&quot;class&quot;</span><span class=\"p\">:</span> <span class=\"s2\">&quot;name-input-class&quot;</span><span class=\"p\">}),</span>\n    <span class=\"p\">)</span>\n    email <span class=\"o\">=</span> forms<span class=\"o\">.</span>EmailField<span class=\"p\">(</span>label<span class=\"o\">=</span><span class=\"s2\">&quot;Your Email&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>When rendering a <code class=\"docutils literal notranslate\">CustomForm</code> instance, the following HTML is included:</p>\n<div class=\"code-block\" data-language=\"html\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Html</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Html code\"><code><span class=\"p\">&lt;</span><span class=\"nt\">div</span> <span class=\"na\">class</span><span class=\"o\">=</span><span class=\"s\">&quot;custom&quot;</span><span class=\"p\">&gt;</span>\n  <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;id_name&quot;</span><span class=\"p\">&gt;</span>Your Name:<span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;</span>\n  <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;text&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;name&quot;</span> <span class=\"na\">class</span><span class=\"o\">=</span><span class=\"s\">&quot;name-input-class&quot;</span> <span class=\"na\">maxlength</span><span class=\"o\">=</span><span class=\"s\">&quot;100&quot;</span> <span class=\"na\">id</span><span class=\"o\">=</span><span class=\"s\">&quot;id_name&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">div</span><span class=\"p\">&gt;</span>\n\n<span class=\"p\">&lt;</span><span class=\"nt\">div</span> <span class=\"na\">class</span><span class=\"o\">=</span><span class=\"s\">&quot;custom&quot;</span><span class=\"p\">&gt;</span>\n  <span class=\"p\">&lt;</span><span class=\"nt\">label</span> <span class=\"na\">for</span><span class=\"o\">=</span><span class=\"s\">&quot;id_email&quot;</span><span class=\"p\">&gt;</span>Your Email:<span class=\"p\">&lt;/</span><span class=\"nt\">label</span><span class=\"p\">&gt;</span>\n  <span class=\"p\">&lt;</span><span class=\"nt\">input</span> <span class=\"na\">type</span><span class=\"o\">=</span><span class=\"s\">&quot;email&quot;</span> <span class=\"na\">name</span><span class=\"o\">=</span><span class=\"s\">&quot;email&quot;</span> <span class=\"na\">maxlength</span><span class=\"o\">=</span><span class=\"s\">&quot;320&quot;</span> <span class=\"na\">required</span><span class=\"o\">=</span><span class=\"s\">&quot;&quot;</span> <span class=\"na\">id</span><span class=\"o\">=</span><span class=\"s\">&quot;id_email&quot;</span><span class=\"p\">&gt;</span>\n<span class=\"p\">&lt;/</span><span class=\"nt\">div</span><span class=\"p\">&gt;</span>\n</code></pre></div>\n<p>See <a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#custom-boundfield\"><span class=\"std std-ref\">Customizing BoundField</span></a> for more details about this feature.</p>\n</section>\n<section id=\"minor-features\">\n<h3>Minor features<a class=\"heading-anchor\" href=\"#minor-features\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<section id=\"django-contrib-admin\">\n<h4><a class=\"reference internal\" href=\"/en/dev/ref/contrib/admin/#module-django.contrib.admin\" title=\"django.contrib.admin: Django's admin site.\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.admin</code></a><a class=\"heading-anchor\" href=\"#django-contrib-admin\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The <code class=\"docutils literal notranslate\">admin/base.html</code> template now has a new block\n<a class=\"reference internal\" href=\"/en/dev/ref/contrib/admin/#extrabody\"><span class=\"std std-ref\">extrabody</span></a> for adding custom code before the closing\n<code class=\"docutils literal notranslate\">&lt;/body&gt;</code> tag.</p></li>\n<li><p>The value of a <a class=\"reference internal\" href=\"/en/dev/ref/models/fields/#django.db.models.URLField\" title=\"django.db.models.URLField\"><code class=\"xref py py-class docutils literal notranslate\">URLField</code></a> now renders as a link.</p></li>\n</ul>\n</section>\n<section id=\"django-contrib-admindocs\">\n<h4><a class=\"reference internal\" href=\"/en/dev/ref/contrib/admin/admindocs/#module-django.contrib.admindocs\" title=\"django.contrib.admindocs: Django's admin documentation generator.\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.admindocs</code></a><a class=\"heading-anchor\" href=\"#django-contrib-admindocs\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>Links to components in docstrings now supports custom link text, using the\nformat <code class=\"docutils literal notranslate\">:role:`link text &lt;link&gt;`</code>. See <a class=\"reference internal\" href=\"/en/dev/ref/contrib/admin/admindocs/#admindocs-helpers\"><span class=\"std std-ref\">documentation helpers</span></a> for more details.</p></li>\n<li><p>The <a class=\"reference internal\" href=\"/en/dev/ref/contrib/admin/admindocs/#admindocs-model-reference\"><span class=\"std std-ref\">model pages</span></a> are now restricted to\nusers with the corresponding view or change permissions.</p></li>\n</ul>\n</section>\n<section id=\"django-contrib-auth\">\n<h4><a class=\"reference internal\" href=\"/en/dev/topics/auth/#module-django.contrib.auth\" title=\"django.contrib.auth: Django's authentication framework.\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.auth</code></a><a class=\"heading-anchor\" href=\"#django-contrib-auth\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The default iteration count for the PBKDF2 password hasher is increased from\n870,000 to 1,000,000.</p></li>\n<li><p>The following new asynchronous methods are now provided, using an <code class=\"docutils literal notranslate\">a</code>\nprefix:</p>\n<ul>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.UserManager.acreate_user\" title=\"django.contrib.auth.models.UserManager.acreate_user\"><code class=\"xref py py-meth docutils literal notranslate\">UserManager.acreate_user()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.UserManager.acreate_superuser\" title=\"django.contrib.auth.models.UserManager.acreate_superuser\"><code class=\"xref py py-meth docutils literal notranslate\">UserManager.acreate_superuser()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/topics/auth/customizing/#django.contrib.auth.models.BaseUserManager.aget_by_natural_key\" title=\"django.contrib.auth.models.BaseUserManager.aget_by_natural_key\"><code class=\"xref py py-meth docutils literal notranslate\">BaseUserManager.aget_by_natural_key()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.aget_user_permissions\" title=\"django.contrib.auth.models.User.aget_user_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">User.aget_user_permissions()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.aget_all_permissions\" title=\"django.contrib.auth.models.User.aget_all_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">User.aget_all_permissions()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.aget_group_permissions\" title=\"django.contrib.auth.models.User.aget_group_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">User.aget_group_permissions()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.ahas_perm\" title=\"django.contrib.auth.models.User.ahas_perm\"><code class=\"xref py py-meth docutils literal notranslate\">User.ahas_perm()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.ahas_perms\" title=\"django.contrib.auth.models.User.ahas_perms\"><code class=\"xref py py-meth docutils literal notranslate\">User.ahas_perms()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.User.ahas_module_perms\" title=\"django.contrib.auth.models.User.ahas_module_perms\"><code class=\"xref py py-meth docutils literal notranslate\">User.ahas_module_perms()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend.aauthenticate\" title=\"django.contrib.auth.backends.ModelBackend.aauthenticate\"><code class=\"xref py py-meth docutils literal notranslate\">ModelBackend.aauthenticate()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend.aget_user_permissions\" title=\"django.contrib.auth.backends.ModelBackend.aget_user_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">ModelBackend.aget_user_permissions()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend.aget_group_permissions\" title=\"django.contrib.auth.backends.ModelBackend.aget_group_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">ModelBackend.aget_group_permissions()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend.aget_all_permissions\" title=\"django.contrib.auth.backends.ModelBackend.aget_all_permissions\"><code class=\"xref py py-meth docutils literal notranslate\">ModelBackend.aget_all_permissions()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend.ahas_perm\" title=\"django.contrib.auth.backends.ModelBackend.ahas_perm\"><code class=\"xref py py-meth docutils literal notranslate\">ModelBackend.ahas_perm()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.ModelBackend.ahas_module_perms\" title=\"django.contrib.auth.backends.ModelBackend.ahas_module_perms\"><code class=\"xref py py-meth docutils literal notranslate\">ModelBackend.ahas_module_perms()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend.aauthenticate\" title=\"django.contrib.auth.backends.RemoteUserBackend.aauthenticate\"><code class=\"xref py py-meth docutils literal notranslate\">RemoteUserBackend.aauthenticate()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.backends.RemoteUserBackend.aconfigure_user\" title=\"django.contrib.auth.backends.RemoteUserBackend.aconfigure_user\"><code class=\"xref py py-meth docutils literal notranslate\">RemoteUserBackend.aconfigure_user()</code></a></p></li>\n</ul>\n</li>\n<li><p>Auth backends can now provide async implementations which are used when\ncalling async auth functions (e.g.\n<a class=\"reference internal\" href=\"/en/dev/topics/auth/default/#django.contrib.auth.aauthenticate\" title=\"django.contrib.auth.aauthenticate\"><code class=\"xref py py-func docutils literal notranslate\">aauthenticate()</code></a>) to reduce context-switching\nwhich improves performance. See <a class=\"reference internal\" href=\"/en/dev/topics/auth/customizing/#writing-authentication-backends-async-interface\"><span class=\"std std-ref\">adding an async interface</span></a> for more details.</p></li>\n<li><p>The <a class=\"reference internal\" href=\"/en/dev/topics/auth/passwords/#included-password-validators\"><span class=\"std std-ref\">password validator classes</span></a>\nnow have a new method <code class=\"docutils literal notranslate\">get_error_message()</code>, which can be overridden in\nsubclasses to customize the error messages.</p></li>\n</ul>\n</section>\n<section id=\"django-contrib-gis\">\n<h4><a class=\"reference internal\" href=\"/en/dev/ref/contrib/gis/#module-django.contrib.gis\" title=\"django.contrib.gis: Geographic Information System (GIS) extensions for Django\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.gis</code></a><a class=\"heading-anchor\" href=\"#django-contrib-gis\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>GDAL now supports curved geometries <code class=\"docutils literal notranslate\">CurvePolygon</code>, <code class=\"docutils literal notranslate\">CompoundCurve</code>,\n<code class=\"docutils literal notranslate\">CircularString</code>, <code class=\"docutils literal notranslate\">MultiSurface</code>, and <code class=\"docutils literal notranslate\">MultiCurve</code> via the new\n<a class=\"reference internal\" href=\"/en/dev/ref/contrib/gis/gdal/#django.contrib.gis.gdal.OGRGeometry.has_curve\" title=\"django.contrib.gis.gdal.OGRGeometry.has_curve\"><code class=\"xref py py-attr docutils literal notranslate\">OGRGeometry.has_curve</code></a> property, and the\n<a class=\"reference internal\" href=\"/en/dev/ref/contrib/gis/gdal/#django.contrib.gis.gdal.OGRGeometry.get_linear_geometry\" title=\"django.contrib.gis.gdal.OGRGeometry.get_linear_geometry\"><code class=\"xref py py-meth docutils literal notranslate\">OGRGeometry.get_linear_geometry()</code></a> and\n<a class=\"reference internal\" href=\"/en/dev/ref/contrib/gis/gdal/#django.contrib.gis.gdal.OGRGeometry.get_curve_geometry\" title=\"django.contrib.gis.gdal.OGRGeometry.get_curve_geometry\"><code class=\"xref py py-meth docutils literal notranslate\">OGRGeometry.get_curve_geometry()</code></a> methods.</p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/gis/geoquerysets/#std-fieldlookup-coveredby\"><code class=\"xref std std-lookup docutils literal notranslate\">coveredby</code></a> and <a class=\"reference internal\" href=\"/en/dev/ref/contrib/gis/geoquerysets/#std-fieldlookup-covers\"><code class=\"xref std std-lookup docutils literal notranslate\">covers</code></a> lookup are now supported on MySQL.</p></li>\n</ul>\n</section>\n<section id=\"django-contrib-syndication\">\n<h4><a class=\"reference internal\" href=\"/en/dev/ref/contrib/syndication/#module-django.contrib.syndication\" title=\"django.contrib.syndication: A framework for generating syndication feeds, in RSS and Atom, quite easily.\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.syndication</code></a><a class=\"heading-anchor\" href=\"#django-contrib-syndication\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>All <a class=\"reference internal\" href=\"/en/dev/ref/utils/#django.utils.feedgenerator.SyndicationFeed\" title=\"django.utils.feedgenerator.SyndicationFeed\"><code class=\"xref py py-class docutils literal notranslate\">SyndicationFeed</code></a> classes now support\na <code class=\"docutils literal notranslate\">stylesheets</code> attribute. If specified, an <code class=\"docutils literal notranslate\">&lt;? xml-stylesheet ?&gt;</code>\nprocessing instruction will be added to the top of the document for each\nstylesheet in the given list. See <a class=\"reference internal\" href=\"/en/dev/ref/contrib/syndication/#feed-stylesheets\"><span class=\"std std-ref\">Feed stylesheets</span></a> for more details.</p></li>\n</ul>\n</section>\n<section id=\"database-backends\">\n<h4>Database backends<a class=\"heading-anchor\" href=\"#database-backends\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>MySQL connections now default to using the <code class=\"docutils literal notranslate\">utf8mb4</code> character set,\ninstead of <code class=\"docutils literal notranslate\">utf8</code>, which is an alias for the deprecated character set\n<code class=\"docutils literal notranslate\">utf8mb3</code>.</p></li>\n<li><p>Oracle backends now support <a class=\"reference internal\" href=\"/en/dev/ref/databases/#oracle-pool\"><span class=\"std std-ref\">connection pools</span></a>, by setting\n<code class=\"docutils literal notranslate\">&quot;pool&quot;</code> in the <a class=\"reference internal\" href=\"/en/dev/ref/settings/#std-setting-OPTIONS\"><code class=\"xref std std-setting docutils literal notranslate\">OPTIONS</code></a> part of your database configuration.</p></li>\n</ul>\n</section>\n<section id=\"decorators\">\n<h4>Decorators<a class=\"heading-anchor\" href=\"#decorators\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/utils/#django.utils.decorators.method_decorator\" title=\"django.utils.decorators.method_decorator\"><code class=\"xref py py-func docutils literal notranslate\">method_decorator()</code></a> now supports wrapping\nasynchronous view methods.</p></li>\n</ul>\n</section>\n<section id=\"email\">\n<h4>Email<a class=\"heading-anchor\" href=\"#email\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>Tuple items of <a class=\"reference internal\" href=\"/en/dev/topics/email/#django.core.mail.EmailMessage\" title=\"django.core.mail.EmailMessage\"><code class=\"xref py py-class docutils literal notranslate\">EmailMessage.attachments</code></a> and\n<a class=\"reference internal\" href=\"/en/dev/topics/email/#django.core.mail.EmailMultiAlternatives\" title=\"django.core.mail.EmailMultiAlternatives\"><code class=\"xref py py-class docutils literal notranslate\">EmailMultiAlternatives.attachments</code></a> are now named tuples, as opposed\nto regular tuples.</p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/topics/email/#django.core.mail.EmailMultiAlternatives.alternatives\" title=\"django.core.mail.EmailMultiAlternatives.alternatives\"><code class=\"xref py py-attr docutils literal notranslate\">EmailMultiAlternatives.alternatives</code></a> is now a list of\nnamed tuples, as opposed to regular tuples.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/topics/email/#django.core.mail.EmailMultiAlternatives.body_contains\" title=\"django.core.mail.EmailMultiAlternatives.body_contains\"><code class=\"xref py py-meth docutils literal notranslate\">body_contains()</code></a> method\nreturns a boolean indicating whether a provided text is contained in the\nemail <code class=\"docutils literal notranslate\">body</code> and in all attached MIME type <code class=\"docutils literal notranslate\">text/*</code> alternatives.</p></li>\n</ul>\n</section>\n<section id=\"error-reporting\">\n<h4>Error Reporting<a class=\"heading-anchor\" href=\"#error-reporting\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The attribute <a class=\"reference internal\" href=\"/en/dev/howto/error-reporting/#django.views.debug.SafeExceptionReporterFilter.hidden_settings\" title=\"django.views.debug.SafeExceptionReporterFilter.hidden_settings\"><code class=\"xref py py-attr docutils literal notranslate\">SafeExceptionReporterFilter.hidden_settings</code></a> now\ntreats values as sensitive if their name includes <code class=\"docutils literal notranslate\">AUTH</code>.</p></li>\n</ul>\n</section>\n<section id=\"forms\">\n<h4>Forms<a class=\"heading-anchor\" href=\"#forms\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/forms/widgets/#django.forms.ColorInput\" title=\"django.forms.ColorInput\"><code class=\"xref py py-class docutils literal notranslate\">ColorInput</code></a> form widget is for entering a color\nin <code class=\"docutils literal notranslate\">rrggbb</code> hexadecimal format and renders as <code class=\"docutils literal notranslate\">&lt;input type=&quot;color&quot; ...&gt;</code>.\nSome browsers support a visual color picker interface for this input type.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/forms/widgets/#django.forms.SearchInput\" title=\"django.forms.SearchInput\"><code class=\"xref py py-class docutils literal notranslate\">SearchInput</code></a> form widget is for entering search\nqueries and renders as <code class=\"docutils literal notranslate\">&lt;input type=&quot;search&quot; ...&gt;</code>.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/forms/widgets/#django.forms.TelInput\" title=\"django.forms.TelInput\"><code class=\"xref py py-class docutils literal notranslate\">TelInput</code></a> form widget is for entering telephone\nnumbers and renders as <code class=\"docutils literal notranslate\">&lt;input type=&quot;tel&quot; ...&gt;</code>.</p></li>\n<li><p>The new <code class=\"docutils literal notranslate\">field_id</code> argument for <a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#django.forms.ErrorList\" title=\"django.forms.ErrorList\"><code class=\"xref py py-class docutils literal notranslate\">ErrorList</code></a> allows an\nHTML <code class=\"docutils literal notranslate\">id</code> attribute to be added in the error template. See\n<a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#django.forms.ErrorList.field_id\" title=\"django.forms.ErrorList.field_id\"><code class=\"xref py py-attr docutils literal notranslate\">ErrorList.field_id</code></a> for details.</p></li>\n<li><p>An <a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#django.forms.BoundField.aria_describedby\" title=\"django.forms.BoundField.aria_describedby\"><code class=\"xref py py-attr docutils literal notranslate\">aria_describedby</code></a> property is added to\n<code class=\"docutils literal notranslate\">BoundField</code> to ease use of this HTML attribute in templates.</p></li>\n<li><p>To improve accessibility for screen reader users <code class=\"docutils literal notranslate\">aria-describedby</code> is used\nto associate form fields with their error messages. See\n<a class=\"reference internal\" href=\"/en/dev/ref/forms/api/#form-error-display\"><span class=\"std std-ref\">how form errors are displayed</span></a> for details.</p></li>\n<li><p>The new asset object <a class=\"reference internal\" href=\"/en/dev/topics/forms/media/#django.forms.Script\" title=\"django.forms.Script\"><code class=\"xref py py-class docutils literal notranslate\">Script</code></a> is available for adding\ncustom HTML-attributes to JavaScript in form media. See\n<a class=\"reference internal\" href=\"/en/dev/topics/forms/media/#form-media-asset-objects\"><span class=\"std std-ref\">paths as objects</span></a> for more details.</p></li>\n</ul>\n</section>\n<section id=\"management-commands\">\n<h4>Management Commands<a class=\"heading-anchor\" href=\"#management-commands\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>A new warning is displayed when running <a class=\"reference internal\" href=\"/en/dev/ref/django-admin/#django-admin-runserver\"><code class=\"xref std std-djadmin docutils literal notranslate\">runserver</code></a>, indicating that\nit is unsuitable for production. This warning can be suppressed by setting\nthe <span class=\"target\" id=\"index-0\"></span><a class=\"reference internal\" href=\"/en/dev/ref/django-admin/#envvar-DJANGO_RUNSERVER_HIDE_WARNING\"><code class=\"xref std std-envvar docutils literal notranslate\">DJANGO_RUNSERVER_HIDE_WARNING</code></a> environment variable to\n<code class=\"docutils literal notranslate\">&quot;true&quot;</code>.</p></li>\n<li><p>The <a class=\"reference internal\" href=\"/en/dev/ref/django-admin/#django-admin-makemigrations\"><code class=\"xref std std-djadmin docutils literal notranslate\">makemigrations</code></a> and <a class=\"reference internal\" href=\"/en/dev/ref/django-admin/#django-admin-migrate\"><code class=\"xref std std-djadmin docutils literal notranslate\">migrate</code></a> commands  have a new\n<code class=\"docutils literal notranslate\">Command.autodetector</code> attribute for subclasses to override in order to use\na custom autodetector class.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/howto/custom-management-commands/#django.core.management.BaseCommand.get_check_kwargs\" title=\"django.core.management.BaseCommand.get_check_kwargs\"><code class=\"xref py py-meth docutils literal notranslate\">BaseCommand.get_check_kwargs()</code></a> method can be overridden in\ncustom commands to control the running of system checks, e.g. to opt into\ndatabase-dependent checks.</p></li>\n</ul>\n</section>\n<section id=\"migrations\">\n<h4>Migrations<a class=\"heading-anchor\" href=\"#migrations\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The new operation <a class=\"reference internal\" href=\"/en/dev/ref/migration-operations/#django.db.migrations.operations.AlterConstraint\" title=\"django.db.migrations.operations.AlterConstraint\"><code class=\"xref py py-class docutils literal notranslate\">AlterConstraint</code></a> is a no-op operation that alters\nconstraints without dropping and recreating constraints in the database.</p></li>\n</ul>\n</section>\n<section id=\"models\">\n<h4>Models<a class=\"heading-anchor\" href=\"#models\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The <code class=\"docutils literal notranslate\">SELECT</code> clause generated when using <a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values\" title=\"django.db.models.query.QuerySet.values\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.values()</code></a> and\n<a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.values_list\" title=\"django.db.models.query.QuerySet.values_list\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.values_list()</code></a> now matches the specified order of the\nreferenced expressions. Previously, the order was based on a set of\ncounterintuitive rules which made query combination through methods such as\n<a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.union\" title=\"django.db.models.query.QuerySet.union\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.union()</code></a> unpredictable.</p></li>\n<li><p>Added support for validation of model constraints which use a\n<a class=\"reference internal\" href=\"/en/dev/ref/models/fields/#django.db.models.GeneratedField\" title=\"django.db.models.GeneratedField\"><code class=\"xref py py-class docutils literal notranslate\">GeneratedField</code></a>.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/models/expressions/#django.db.models.Expression.set_returning\" title=\"django.db.models.Expression.set_returning\"><code class=\"xref py py-attr docutils literal notranslate\">Expression.set_returning</code></a> attribute specifies that the\nexpression contains a set-returning function, enforcing subquery evaluation.\nThis is necessary for many Postgres set-returning functions.</p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/fields/#django.db.models.CharField.max_length\" title=\"django.db.models.CharField.max_length\"><code class=\"xref py py-attr docutils literal notranslate\">CharField.max_length</code></a> is no\nlonger required to be set on SQLite, which supports unlimited <code class=\"docutils literal notranslate\">VARCHAR</code>\ncolumns.</p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.explain\" title=\"django.db.models.query.QuerySet.explain\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.explain()</code></a> now supports the <code class=\"docutils literal notranslate\">memory</code> and <code class=\"docutils literal notranslate\">serialize</code>\noptions on PostgreSQL 17+.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/models/database-functions/#django.db.models.functions.JSONArray\" title=\"django.db.models.functions.JSONArray\"><code class=\"xref py py-class docutils literal notranslate\">JSONArray</code></a> database function\naccepts a list of field names or expressions and returns a JSON array\ncontaining those values.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/models/expressions/#django.db.models.Expression.allows_composite_expressions\" title=\"django.db.models.Expression.allows_composite_expressions\"><code class=\"xref py py-attr docutils literal notranslate\">Expression.allows_composite_expressions</code></a> attribute specifies\nthat the expression allows composite expressions, for example, to support\n<a class=\"reference internal\" href=\"/en/dev/topics/composite-primary-key/#cpk-and-database-functions\"><span class=\"std std-ref\">composite primary keys</span></a>.</p></li>\n</ul>\n</section>\n<section id=\"requests-and-responses\">\n<h4>Requests and Responses<a class=\"heading-anchor\" href=\"#requests-and-responses\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/request-response/#django.http.HttpResponse.text\" title=\"django.http.HttpResponse.text\"><code class=\"xref py py-attr docutils literal notranslate\">HttpResponse.text</code></a> property provides the string\nrepresentation of <a class=\"reference internal\" href=\"/en/dev/ref/request-response/#django.http.HttpResponse.content\" title=\"django.http.HttpResponse.content\"><code class=\"xref py py-attr docutils literal notranslate\">HttpResponse.content</code></a>.</p></li>\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/request-response/#django.http.HttpRequest.get_preferred_type\" title=\"django.http.HttpRequest.get_preferred_type\"><code class=\"xref py py-meth docutils literal notranslate\">HttpRequest.get_preferred_type()</code></a> method can be used to query\nthe preferred media type the client accepts.</p></li>\n<li><p>The new <code class=\"docutils literal notranslate\">preserve_request</code> argument for\n<a class=\"reference internal\" href=\"/en/dev/ref/request-response/#django.http.HttpResponseRedirect\" title=\"django.http.HttpResponseRedirect\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponseRedirect</code></a> and\n<a class=\"reference internal\" href=\"/en/dev/ref/request-response/#django.http.HttpResponsePermanentRedirect\" title=\"django.http.HttpResponsePermanentRedirect\"><code class=\"xref py py-class docutils literal notranslate\">HttpResponsePermanentRedirect</code></a>\ndetermines whether the HTTP status codes 302/307 or 301/308 are used,\nrespectively.</p></li>\n<li><p>The new <code class=\"docutils literal notranslate\">preserve_request</code> argument for\n<a class=\"reference internal\" href=\"/en/dev/topics/http/shortcuts/#django.shortcuts.redirect\" title=\"django.shortcuts.redirect\"><code class=\"xref py py-func docutils literal notranslate\">redirect()</code></a> allows to instruct the user agent to reuse\nthe HTTP method and body during redirection using specific status codes.</p></li>\n</ul>\n</section>\n<section id=\"serialization\">\n<h4>Serialization<a class=\"heading-anchor\" href=\"#serialization\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>Each serialization format now defines a <code class=\"docutils literal notranslate\">Deserializer</code> class, rather than a\nfunction, to improve extensibility when defining a\n<a class=\"reference internal\" href=\"/en/dev/topics/serialization/#custom-serialization-formats\"><span class=\"std std-ref\">custom serialization format</span></a>.</p></li>\n</ul>\n</section>\n<section id=\"templates\">\n<h4>Templates<a class=\"heading-anchor\" href=\"#templates\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/howto/custom-template-tags/#django.template.Library.simple_block_tag\" title=\"django.template.Library.simple_block_tag\"><code class=\"xref py py-meth docutils literal notranslate\">simple_block_tag()</code></a> decorator enables\nthe creation of simple block tags, which can accept and use a section of the\ntemplate.</p></li>\n</ul>\n</section>\n<section id=\"tests\">\n<h4>Tests<a class=\"heading-anchor\" href=\"#tests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p>Stack frames from Django’s custom assertions are now hidden. This makes test\nfailures easier to read and enables <a class=\"reference internal\" href=\"/en/dev/ref/django-admin/#cmdoption-test-pdb\"><code class=\"xref std std-option docutils literal notranslate\">test --pdb</code></a> to directly enter\ninto the failing test method.</p></li>\n<li><p>Data loaded from <a class=\"reference internal\" href=\"/en/dev/topics/testing/tools/#django.test.TransactionTestCase.fixtures\" title=\"django.test.TransactionTestCase.fixtures\"><code class=\"xref py py-attr docutils literal notranslate\">fixtures</code></a> and from\nmigrations enabled with <a class=\"reference internal\" href=\"/en/dev/topics/testing/overview/#test-case-serialized-rollback\"><span class=\"std std-ref\">serialized_rollback=True</span></a> are now available during\n<code class=\"docutils literal notranslate\">TransactionTestCase.setUpClass()</code>.</p></li>\n</ul>\n</section>\n<section id=\"urls\">\n<h4>URLs<a class=\"heading-anchor\" href=\"#urls\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/urlresolvers/#django.urls.reverse\" title=\"django.urls.reverse\"><code class=\"xref py py-func docutils literal notranslate\">reverse()</code></a> and <a class=\"reference internal\" href=\"/en/dev/ref/urlresolvers/#django.urls.reverse_lazy\" title=\"django.urls.reverse_lazy\"><code class=\"xref py py-func docutils literal notranslate\">reverse_lazy()</code></a> now accept\n<code class=\"docutils literal notranslate\">query</code> and <code class=\"docutils literal notranslate\">fragment</code> keyword arguments, allowing the addition of a\nquery string and/or fragment identifier in the generated URL, respectively.</p></li>\n</ul>\n</section>\n<section id=\"utilities\">\n<h4>Utilities<a class=\"heading-anchor\" href=\"#utilities\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<ul class=\"simple\">\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/utils/#django.utils.safestring.SafeString\" title=\"django.utils.safestring.SafeString\"><code class=\"xref py py-class docutils literal notranslate\">SafeString</code></a> now returns\n<a class=\"reference external\" href=\"https://docs.python.org/3/library/constants.html#NotImplemented\" title=\"(in Python v3.14)\"><code class=\"xref py py-data docutils literal notranslate\">NotImplemented</code></a> in <code class=\"docutils literal notranslate\">__add__</code> for non-string right-hand side\nvalues. This aligns with the <a class=\"reference external\" href=\"https://docs.python.org/3/library/stdtypes.html#str\" title=\"(in Python v3.14)\"><code class=\"xref py py-class docutils literal notranslate\">str</code></a> addition behavior and allows\n<code class=\"docutils literal notranslate\">__radd__</code> to be used if available.</p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/utils/#django.utils.html.format_html_join\" title=\"django.utils.html.format_html_join\"><code class=\"xref py py-func docutils literal notranslate\">format_html_join()</code></a> now supports taking an iterable\nof mappings, passing their contents as keyword arguments to\n<a class=\"reference internal\" href=\"/en/dev/ref/utils/#django.utils.html.format_html\" title=\"django.utils.html.format_html\"><code class=\"xref py py-func docutils literal notranslate\">format_html()</code></a>.</p></li>\n</ul>\n</section>\n</section>\n</section>\n<section id=\"backwards-incompatible-changes-in-5-2\">\n<span id=\"backwards-incompatible-5-2\"></span><h2>Backwards incompatible changes in 5.2<a class=\"heading-anchor\" href=\"#backwards-incompatible-changes-in-5-2\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"database-backend-api\">\n<h3>Database backend API<a class=\"heading-anchor\" href=\"#database-backend-api\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>This section describes changes that may be needed in third-party database\nbackends.</p>\n<ul class=\"simple\">\n<li><p>The new <a class=\"reference internal\" href=\"/en/dev/ref/models/instances/#django.db.models.Model._is_pk_set\" title=\"django.db.models.Model._is_pk_set\"><code class=\"xref py py-meth docutils literal notranslate\">Model._is_pk_set()</code></a> method\nallows checking if a Model instance’s primary key is defined.</p></li>\n<li><p><code class=\"docutils literal notranslate\">BaseDatabaseOperations.adapt_decimalfield_value()</code> is now a no-op, simply\nreturning the given value.</p></li>\n</ul>\n</section>\n<section id=\"id1\">\n<h3><a class=\"reference internal\" href=\"/en/dev/ref/contrib/gis/#module-django.contrib.gis\" title=\"django.contrib.gis: Geographic Information System (GIS) extensions for Django\"><code class=\"xref py py-mod docutils literal notranslate\">django.contrib.gis</code></a><a class=\"heading-anchor\" href=\"#id1\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<ul class=\"simple\">\n<li><p>Support for PostGIS 3.0 is removed.</p></li>\n<li><p>Support for GDAL 3.0 is removed.</p></li>\n</ul>\n</section>\n<section id=\"dropped-support-for-postgresql-13\">\n<h3>Dropped support for PostgreSQL 13<a class=\"heading-anchor\" href=\"#dropped-support-for-postgresql-13\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Upstream support for PostgreSQL 13 ends in November 2025. Django 5.2 supports\nPostgreSQL 14 and higher.</p>\n</section>\n<section id=\"changed-mysql-connection-character-set-default\">\n<h3>Changed MySQL connection character set default<a class=\"heading-anchor\" href=\"#changed-mysql-connection-character-set-default\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>MySQL connections now default to using the <code class=\"docutils literal notranslate\">utf8mb4</code> character set, instead\nof <code class=\"docutils literal notranslate\">utf8</code>, which is an alias for the deprecated character set <code class=\"docutils literal notranslate\">utf8mb3</code>.\n<code class=\"docutils literal notranslate\">utf8mb3</code> can be specified in the <code class=\"docutils literal notranslate\">OPTIONS</code> part of the <code class=\"docutils literal notranslate\">DATABASES</code>\nsetting, if needed for legacy databases.</p>\n</section>\n<section id=\"miscellaneous\">\n<h3>Miscellaneous<a class=\"heading-anchor\" href=\"#miscellaneous\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<ul class=\"simple\">\n<li><p>Adding <a class=\"reference internal\" href=\"/en/dev/topics/email/#django.core.mail.EmailMultiAlternatives.alternatives\" title=\"django.core.mail.EmailMultiAlternatives.alternatives\"><code class=\"xref py py-attr docutils literal notranslate\">EmailMultiAlternatives.alternatives</code></a> is now only supported via\nthe <a class=\"reference internal\" href=\"/en/dev/topics/email/#django.core.mail.EmailMultiAlternatives.attach_alternative\" title=\"django.core.mail.EmailMultiAlternatives.attach_alternative\"><code class=\"xref py py-meth docutils literal notranslate\">attach_alternative()</code></a> method.</p></li>\n<li><p>The minimum supported version of <code class=\"docutils literal notranslate\">gettext</code> is increased from 0.15 to 0.19.</p></li>\n<li><p><code class=\"docutils literal notranslate\">HttpRequest.accepted_types</code> is now sorted by the client’s preference,\nbased on the request’s <code class=\"docutils literal notranslate\">Accept</code> header.</p></li>\n<li><p>The attributes <a class=\"reference internal\" href=\"/en/dev/ref/models/constraints/#django.db.models.UniqueConstraint.violation_error_code\" title=\"django.db.models.UniqueConstraint.violation_error_code\"><code class=\"xref py py-attr docutils literal notranslate\">UniqueConstraint.violation_error_code</code></a> and\n<a class=\"reference internal\" href=\"/en/dev/ref/models/constraints/#django.db.models.UniqueConstraint.violation_error_message\" title=\"django.db.models.UniqueConstraint.violation_error_message\"><code class=\"xref py py-attr docutils literal notranslate\">UniqueConstraint.violation_error_message</code></a> are now always used when\nprovided. Previously, they were ignored if <a class=\"reference internal\" href=\"/en/dev/ref/models/constraints/#django.db.models.UniqueConstraint.fields\" title=\"django.db.models.UniqueConstraint.fields\"><code class=\"xref py py-attr docutils literal notranslate\">UniqueConstraint.fields</code></a>\nwas set without a <a class=\"reference internal\" href=\"/en/dev/ref/models/constraints/#django.db.models.UniqueConstraint.condition\" title=\"django.db.models.UniqueConstraint.condition\"><code class=\"xref py py-attr docutils literal notranslate\">UniqueConstraint.condition</code></a>.</p></li>\n<li><p>The <a class=\"reference internal\" href=\"/en/dev/ref/templates/api/#django.template.context_processors.debug\" title=\"django.template.context_processors.debug\"><code class=\"xref py py-func docutils literal notranslate\">debug()</code></a> context processor is no\nlonger included in the default project template.</p></li>\n<li><p>The following methods now have <code class=\"docutils literal notranslate\">alters_data=True</code> set to prevent side\neffects when <a class=\"reference internal\" href=\"/en/dev/ref/templates/api/#alters-data-description\"><span class=\"std std-ref\">rendering a template context</span></a>:</p>\n<ul>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.UserManager.create_user\" title=\"django.contrib.auth.models.UserManager.create_user\"><code class=\"xref py py-meth docutils literal notranslate\">UserManager.create_user()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.UserManager.acreate_user\" title=\"django.contrib.auth.models.UserManager.acreate_user\"><code class=\"xref py py-meth docutils literal notranslate\">UserManager.acreate_user()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.UserManager.create_superuser\" title=\"django.contrib.auth.models.UserManager.create_superuser\"><code class=\"xref py py-meth docutils literal notranslate\">UserManager.create_superuser()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/contrib/auth/#django.contrib.auth.models.UserManager.acreate_superuser\" title=\"django.contrib.auth.models.UserManager.acreate_superuser\"><code class=\"xref py py-meth docutils literal notranslate\">UserManager.acreate_superuser()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.create\" title=\"django.db.models.query.QuerySet.create\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.create()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.acreate\" title=\"django.db.models.query.QuerySet.acreate\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.acreate()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create\" title=\"django.db.models.query.QuerySet.bulk_create\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.bulk_create()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.abulk_create\" title=\"django.db.models.query.QuerySet.abulk_create\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.abulk_create()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.get_or_create\" title=\"django.db.models.query.QuerySet.get_or_create\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.get_or_create()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.aget_or_create\" title=\"django.db.models.query.QuerySet.aget_or_create\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.aget_or_create()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.update_or_create\" title=\"django.db.models.query.QuerySet.update_or_create\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.update_or_create()</code></a></p></li>\n<li><p><a class=\"reference internal\" href=\"/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.aupdate_or_create\" title=\"django.db.models.query.QuerySet.aupdate_or_create\"><code class=\"xref py py-meth docutils literal notranslate\">QuerySet.aupdate_or_create()</code></a></p></li>\n</ul>\n</li>\n<li><p>The minimum supported version of <code class=\"docutils literal notranslate\">oracledb</code> is increased from 1.3.2 to\n2.3.0.</p></li>\n<li><p>Built-in aggregate functions accepting only one argument (<code class=\"docutils literal notranslate\">Avg</code>, <code class=\"docutils literal notranslate\">Count</code>,\n<code class=\"docutils literal notranslate\">Max</code>, <code class=\"docutils literal notranslate\">Min</code>, <code class=\"docutils literal notranslate\">StdDev</code>, <code class=\"docutils literal notranslate\">Sum</code>, and <code class=\"docutils literal notranslate\">Variance</code>) now raise\n<a class=\"reference external\" href=\"https://docs.python.org/3/library/exceptions.html#TypeError\" title=\"(in Python v3.14)\"><code class=\"xref py py-exc docutils literal notranslate\">TypeError</code></a> when called with an incorrect number of arguments.</p></li>\n</ul>\n</section>\n</section>\n<section id=\"features-deprecated-in-5-2\">\n<span id=\"deprecated-features-5-2\"></span><h2>Features deprecated in 5.2<a class=\"heading-anchor\" href=\"#features-deprecated-in-5-2\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"id2\">\n<h3>Miscellaneous<a class=\"heading-anchor\" href=\"#id2\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<ul class=\"simple\">\n<li><p>The <code class=\"docutils literal notranslate\">all</code> argument for the <code class=\"docutils literal notranslate\">django.contrib.staticfiles.finders.find()</code>\nfunction is deprecated in favor of the <code class=\"docutils literal notranslate\">find_all</code> argument.</p></li>\n<li><p>Fallbacks to <code class=\"docutils literal notranslate\">request.user</code> and <code class=\"docutils literal notranslate\">request.auser()</code> when <code class=\"docutils literal notranslate\">user</code> is\n<code class=\"docutils literal notranslate\">None</code> in <code class=\"docutils literal notranslate\">django.contrib.auth.login()</code> and\n<code class=\"docutils literal notranslate\">django.contrib.auth.alogin()</code>, respectively, are deprecated.</p></li>\n<li><p>The <code class=\"docutils literal notranslate\">ordering</code> keyword argument of the PostgreSQL specific aggregation\nfunctions <code class=\"docutils literal notranslate\">django.contrib.postgres.aggregates.ArrayAgg</code>,\n<code class=\"docutils literal notranslate\">django.contrib.postgres.aggregates.JSONBAgg</code>, and\n<code class=\"docutils literal notranslate\">django.contrib.postgres.aggregates.StringAgg</code> is deprecated in favor\nof the <code class=\"docutils literal notranslate\">order_by</code> argument.</p></li>\n<li><p>Support for subclasses of <code class=\"docutils literal notranslate\">RemoteUserMiddleware</code> that override\n<code class=\"docutils literal notranslate\">process_request()</code> without overriding <code class=\"docutils literal notranslate\">aprocess_request()</code> is\ndeprecated.</p></li>\n</ul>\n</section>\n</section>","rootId":"django-5-2-release-notes","toc":[{"title":"Python compatibility","anchor":"python-compatibility","children":[]},{"title":"What’s new in Django 5.2","anchor":"what-s-new-in-django-5-2","children":[{"title":"Automatic models import in the shell","anchor":"automatic-models-import-in-the-shell","children":[]},{"title":"Composite Primary Keys","anchor":"composite-primary-keys","children":[]},{"title":"Simplified override of BoundField","anchor":"simplified-override-of-boundfield","children":[]},{"title":"Minor features","anchor":"minor-features","children":[{"title":"django.contrib.admin","anchor":"django-contrib-admin","children":[]},{"title":"django.contrib.admindocs","anchor":"django-contrib-admindocs","children":[]},{"title":"django.contrib.auth","anchor":"django-contrib-auth","children":[]},{"title":"django.contrib.gis","anchor":"django-contrib-gis","children":[]},{"title":"django.contrib.syndication","anchor":"django-contrib-syndication","children":[]},{"title":"Database backends","anchor":"database-backends","children":[]},{"title":"Decorators","anchor":"decorators","children":[]},{"title":"Email","anchor":"email","children":[]},{"title":"Error Reporting","anchor":"error-reporting","children":[]},{"title":"Forms","anchor":"forms","children":[]},{"title":"Management Commands","anchor":"management-commands","children":[]},{"title":"Migrations","anchor":"migrations","children":[]},{"title":"Models","anchor":"models","children":[]},{"title":"Requests and Responses","anchor":"requests-and-responses","children":[]},{"title":"Serialization","anchor":"serialization","children":[]},{"title":"Templates","anchor":"templates","children":[]},{"title":"Tests","anchor":"tests","children":[]},{"title":"URLs","anchor":"urls","children":[]},{"title":"Utilities","anchor":"utilities","children":[]}]}]},{"title":"Backwards incompatible changes in 5.2","anchor":"backwards-incompatible-changes-in-5-2","children":[{"title":"Database backend API","anchor":"database-backend-api","children":[]},{"title":"django.contrib.gis","anchor":"id1","children":[]},{"title":"Dropped support for PostgreSQL 13","anchor":"dropped-support-for-postgresql-13","children":[]},{"title":"Changed MySQL connection character set default","anchor":"changed-mysql-connection-character-set-default","children":[]},{"title":"Miscellaneous","anchor":"miscellaneous","children":[]}]},{"title":"Features deprecated in 5.2","anchor":"features-deprecated-in-5-2","children":[{"title":"Miscellaneous","anchor":"id2","children":[]}]}],"breadcrumbs":[{"docname":"releases/index","title":"Release notes","url":"/en/dev/releases/"}],"prev":{"docname":"releases/5.2.1","title":"Django 5.2.1 release notes","url":"/en/dev/releases/5.2.1/"},"next":{"docname":"releases/5.1.15","title":"Django 5.1.15 release notes","url":"/en/dev/releases/5.1.15/"},"formats":{"html":"/en/dev/releases/5.2/","markdown":"/en/dev/releases/5.2.md","json":"/en/dev/releases/5.2.json"},"source":"https://github.com/django/django/blob/main/docs/releases/5.2.txt","official":"https://docs.djangoproject.com/en/dev/releases/5.2/","inVersions":["dev","6.1","6.0","5.2"],"inLocales":["en"]}