Django - 5.0


Django 5.0 release notes

December 4, 2023

Welcome to Django 5.0!

These release notes cover the new features, as well as
some backwards incompatible changes you’ll
want to be aware of when upgrading from Django 4.2 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.

Python compatibility

Django 5.0 supports Python 3.10, 3.11, and 3.12. We highly recommend and
only officially support the latest release of each series.

The Django 4.2.x series is the last to support Python 3.8 and 3.9.

Third-party library support for older version of Django

Following the release of Django 5.0, we suggest that third-party app authors
drop support for all versions of Django prior to 4.2. At that time, you should
be able to run your package’s tests using python -Wd so that deprecation
warnings appear. After making the deprecation warning fixes, your app should be
compatible with Django 5.0.

What’s new in Django 5.0

Facet filters in the admin

Facet counts are now shown for applied filters in the admin changelist when
toggled on via the UI. This behavior can be changed via the new
ModelAdmin.show\_facets attribute. For more information see
Facets.

Simplified templates for form field rendering

Django 5.0 introduces the concept of a field group, and field group templates.
This simplifies rendering of the related elements of a Django form field such
as its label, widget, help text, and errors.

For example, the template below:

<form>
...
<div>
  {{ form.name.label\_tag }}
  {% if form.name.help\_text %}
    <div class="helptext" id="{{ form.name.auto\_id }}\_helptext">
      {{ form.name.help\_text|safe }}
    </div>
  {% endif %}
  {{ form.name.errors }}
  {{ form.name }}
  <div class="row">
    <div class="col">
      {{ form.email.label\_tag }}
      {% if form.email.help\_text %}
        <div class="helptext" id="{{ form.email.auto\_id }}\_helptext">
          {{ form.email.help\_text|safe }}
        </div>
      {% endif %}
      {{ form.email.errors }}
      {{ form.email }}
    </div>
    <div class="col">
      {{ form.password.label\_tag }}
      {% if form.password.help\_text %}
        <div class="helptext" id="{{ form.password.auto\_id }}\_helptext">
          {{ form.password.help\_text|safe }}
        </div>
      {% endif %}
      {{ form.password.errors }}
      {{ form.password }}
    </div>
  </div>
</div>
...
</form>

Can now be simplified to:

<form>
...
<div>
  {{ form.name.as\_field\_group }}
  <div class="row">
    <div class="col">{{ form.email.as\_field\_group }}</div>
    <div class="col">{{ form.password.as\_field\_group }}</div>
  </div>
</div>
...
</form>

as\_field\_group() renders fields with the
"django/forms/field.html" template by default and can be customized on a
per-project, per-field, or per-request basis. See
Reusable field group templates.

Database-computed default values

The new Field.db\_default parameter
sets a database-computed default value. For example:

from django.db import models
from django.db.models.functions import Now, Pi

class MyModel(models.Model):
    age = models.IntegerField(db\_default=18)
    created = models.DateTimeField(db\_default=Now())
    circumference = models.FloatField(db\_default=2 \* Pi())

Database generated model field

The new GeneratedField allows creation of database
generated columns. This field can be used on all supported database backends
to create a field that is always computed from other fields. For example:

from django.db import models
from django.db.models import F

class Square(models.Model):
    side = models.IntegerField()
    area = models.GeneratedField(
        expression=F("side") \* F("side"),
        output\_field=models.BigIntegerField(),
        db\_persist=True,
    )

More options for declaring field choices

Field.choices (for model fields) and ChoiceField.choices
(for form fields) allow for more flexibility when declaring their values. In
previous versions of Django, choices should either be a list of 2-tuples,
or an Enumeration types subclass, but the latter required
accessing the .choices attribute to provide the values in the expected
form:

from django.db import models

Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")

SPORT\_CHOICES = [
    ("Martial Arts", [("judo", "Judo"), ("karate", "Karate")]),
    ("Racket", [("badminton", "Badminton"), ("tennis", "Tennis")]),
    ("unknown", "Unknown"),
]

class Winner(models.Model):
    name = models.CharField(...)
    medal = models.CharField(..., choices=Medal.choices)
    sport = models.CharField(..., choices=SPORT\_CHOICES)

Django 5.0 adds support for accepting a mapping or a callable instead of an
iterable, and also no longer requires .choices to be used directly to
expand enumeration types:

from django.db import models

Medal = models.TextChoices("Medal", "GOLD SILVER BRONZE")

SPORT\_CHOICES = {  # Using a mapping instead of a list of 2-tuples.
    "Martial Arts": {"judo": "Judo", "karate": "Karate"},
    "Racket": {"badminton": "Badminton", "tennis": "Tennis"},
    "unknown": "Unknown",
}

def get\_scores():
    return [(i, str(i)) for i in range(10)]

class Winner(models.Model):
    name = models.CharField(...)
    medal = models.CharField(..., choices=Medal)  # Using `.choices` not required.
    sport = models.CharField(..., choices=SPORT\_CHOICES)
    score = models.IntegerField(choices=get\_scores)  # A callable is allowed.

Under the hood the provided choices are normalized into a list of 2-tuples
as the canonical form whenever the choices value is updated. For more
information, please check the model field reference on choices.

Minor features

django.contrib.admin

  • The new AdminSite.get\_log\_entries() method allows customizing the
    queryset for the site’s listed log entries.
  • The django.contrib.admin.AllValuesFieldListFilter,
    ChoicesFieldListFilter, RelatedFieldListFilter, and
    RelatedOnlyFieldListFilter admin filters now handle multi-valued query
    parameters.
  • XRegExp is upgraded from version 3.2.0 to 5.1.1.
  • The new AdminSite.get\_model\_admin() method returns an admin class for
    the given model class.
  • Properties in ModelAdmin.list\_display now support boolean
    attribute.
  • jQuery is upgraded from version 3.6.4 to 3.7.1.

django.contrib.auth

django.contrib.contenttypes

django.contrib.gis

  • The new
    ClosestPoint()
    function returns a 2-dimensional point on the geometry that is closest to
    another geometry.
  • GIS aggregates now support the filter
    argument.
  • Support for GDAL 3.7 and GEOS 3.12 is added.
  • The new GEOSGeometry.equals\_identical() method allows point-wise
    equivalence checking of geometries.

django.contrib.messages

django.contrib.postgres

Asynchronous views

  • Under ASGI, http.disconnect events are now handled. This allows views to
    perform any necessary cleanup if a client disconnects before the response is
    generated. See Handling disconnects for more details.

Decorators

Error Reporting

File Storage

  • File.open() now passes all positional (\*args) and keyword
    arguments (\*\*kwargs) to Python’s built-in open().

Forms

  • The new assume\_scheme argument for
    URLField allows specifying a default URL scheme.
  • In order to improve accessibility, the following changes are made:
    • Form fields now include the aria-describedby HTML attribute to enable
      screen readers to associate form fields with their help text.
    • Invalid form fields now include the aria-invalid="true" HTML attribute.

Internationalization

  • Support and translations for the Uyghur language are now available.

Migrations

Models

Pagination

Signals

  • The new Signal.asend() and Signal.asend\_robust() methods allow
    asynchronous signal dispatch. Signal receivers may be synchronous or
    asynchronous, and will be automatically adapted to the correct calling style.

Templates

  • The new escapeseq template filter applies escape to
    each element of a sequence.

Tests

Validators

  • The new offset argument of
    StepValueValidator allows specifying an
    offset for valid values.

Backwards incompatible changes in 5.0

Database backend API

This section describes changes that may be needed in third-party database
backends.

  • DatabaseFeatures.supports\_expression\_defaults should be set to False
    if the database doesn’t support using database functions as defaults.
  • DatabaseFeatures.supports\_default\_keyword\_in\_insert should be set to
    False if the database doesn’t support the DEFAULT keyword in
    INSERT queries.
  • DatabaseFeatures.supports\_default\_keyword\_in\_bulk\_insert should be set to
    False if the database doesn’t support the DEFAULT keyword in bulk
    INSERT queries.

django.contrib.gis

  • Support for GDAL 2.2 and 2.3 is removed.
  • Support for GEOS 3.6 and 3.7 is removed.

django.contrib.sitemaps

  • The django.contrib.sitemaps.ping\_google() function and the
    ping\_google management command are removed as the Google
    Sitemaps ping endpoint is deprecated and will be removed in January 2024.
  • The django.contrib.sitemaps.SitemapNotFound exception class is removed.

Dropped support for MySQL < 8.0.11

Support for pre-releases of MySQL 8.0.x series is removed. Django 5.0 supports
MySQL 8.0.11 and higher.

Using create\_defaults\_\_exact may now be required with QuerySet.update\_or\_create()

QuerySet.update\_or\_create() now supports the parameter
create\_defaults. As a consequence, any models that have a field named
create\_defaults that are used with an update\_or\_create() should specify
the field in the lookup with create\_defaults\_\_exact.

Migrating existing UUIDField on MariaDB 10.7+

On MariaDB 10.7+, UUIDField is now created as UUID column rather than
CHAR(32) column. As a consequence, any UUIDField created in
Django < 5.0 should be replaced with a UUIDField subclass backed by
CHAR(32):

class Char32UUIDField(models.UUIDField):
    def db\_type(self, connection):
        return "char(32)"

For example:

class MyModel(models.Model):
    uuid = models.UUIDField(primary\_key=True, default=uuid.uuid4)

Should become:

class Char32UUIDField(models.UUIDField):
    def db\_type(self, connection):
        return "char(32)"

class MyModel(models.Model):
    uuid = Char32UUIDField(primary\_key=True, default=uuid.uuid4)

Running the makemigrations command will generate a migration
containing a no-op AlterField operation.

Miscellaneous

  • The instance argument of the undocumented
    BaseModelFormSet.save\_existing() method is renamed to obj.
  • The undocumented django.contrib.admin.helpers.checkbox is removed.
  • Integer fields are now validated as 64-bit integers on SQLite to match the
    behavior of sqlite3.
  • The undocumented Query.annotation\_select\_mask attribute is changed from a
    set of strings to an ordered list of strings.
  • ImageField.update\_dimension\_fields() is no longer called on the
    post\_init signal if width\_field and height\_field are not set.
  • Now database function now uses
    LOCALTIMESTAMP instead of CURRENT\_TIMESTAMP on Oracle.
  • AdminSite.site\_header is now rendered in a <div> tag instead of
    <h1>. Screen reader users rely on heading elements for navigation within
    a page. Having two <h1> elements was confusing and the site header wasn’t
    helpful as it is repeated on all pages.
  • In order to improve accessibility, the admin’s main content area and header
    content area are now rendered in a <main> and <header> tag instead of
    <div>.
  • On databases without native support for the SQL XOR operator, ^ as
    the exclusive or (XOR) operator now returns rows that are matched by an
    odd number of operands rather than exactly one operand. This is consistent
    with the behavior of MySQL, MariaDB, and Python.
  • The minimum supported version of asgiref is increased from 3.6.0 to
    3.7.0.
  • The minimum supported version of selenium is increased from 3.8.0 to
    4.8.0.
  • The AlreadyRegistered and NotRegistered exceptions are moved from
    django.contrib.admin.sites to django.contrib.admin.exceptions.
  • The minimum supported version of SQLite is increased from 3.21.0 to 3.27.0.
  • Support for cx\_Oracle < 8.3 is removed.
  • Executing SQL queries before the app registry has been fully populated now
    raises RuntimeWarning.
  • BadRequest is raised for non-UTF-8 encoded
    requests with the application/x-www-form-urlencoded content type.
    See RFC 1866 for more details.
  • The minimum supported version of colorama is increased to 0.4.6.
  • The minimum supported version of docutils is increased to 0.19.

Features deprecated in 5.0

Miscellaneous

  • The DjangoDivFormRenderer and Jinja2DivFormRenderer transitional form
    renderers are deprecated.
  • Passing positional arguments name and violation\_error\_message to
    BaseConstraint is deprecated in favor of
    keyword-only arguments.
  • request is added to the signature of ModelAdmin.lookup\_allowed().
    Support for ModelAdmin subclasses that do not accept this argument is
    deprecated.
  • The get\_joining\_columns() method of ForeignObject and
    ForeignObjectRel is deprecated. Starting with Django 6.0,
    django.db.models.sql.datastructures.Join will no longer fallback to
    get\_joining\_columns(). Subclasses should implement
    get\_joining\_fields() instead.
  • The ForeignObject.get\_reverse\_joining\_columns() method is deprecated.
  • The default scheme for forms.URLField will change from "http" to
    "https" in Django 6.0. Set FORMS\_URLFIELD\_ASSUME\_HTTPS
    transitional setting to True to opt into assuming "https" during the
    Django 5.x release cycle.
  • FORMS\_URLFIELD\_ASSUME\_HTTPS transitional setting is deprecated.
  • Support for calling format\_html() without passing args or kwargs will be
    removed.
  • Support for cx\_Oracle is deprecated in favor of oracledb 1.3.2+ Python
    driver.
  • DatabaseOperations.field\_cast\_sql() is deprecated in favor of
    DatabaseOperations.lookup\_cast(). Starting with Django 6.0,
    BuiltinLookup.process\_lhs() will no longer call field\_cast\_sql().
    Third-party database backends should implement lookup\_cast() instead.
  • The django.db.models.enums.ChoicesMeta metaclass is renamed to
    ChoicesType.
  • The Prefetch.get\_current\_queryset() method is deprecated.
  • The get\_prefetch\_queryset() method of related managers and descriptors
    is deprecated. Starting with Django 6.0, get\_prefetcher() and
    prefetch\_related\_objects() will no longer fallback to
    get\_prefetch\_queryset(). Subclasses should implement
    get\_prefetch\_querysets() instead.

Features removed in 5.0

These features have reached the end of their deprecation cycle and are removed
in Django 5.0.

See Features deprecated in 4.0 for details on these changes, including how
to remove usage of these features.

  • The SERIALIZE test setting is removed.
  • The undocumented django.utils.baseconv module is removed.
  • The undocumented django.utils.datetime\_safe module is removed.
  • The default value of the USE\_TZ setting is changed from False to
    True.
  • The default sitemap protocol for sitemaps built outside the context of a
    request is changed from 'http' to 'https'.
  • The extra\_tests argument for DiscoverRunner.build\_suite() and
    DiscoverRunner.run\_tests() is removed.
  • The django.contrib.postgres.aggregates.ArrayAgg, JSONBAgg, and
    StringAgg aggregates no longer return [], [], and '',
    respectively, when there are no rows.
  • The USE\_L10N setting is removed.
  • The USE\_DEPRECATED\_PYTZ transitional setting is removed.
  • Support for pytz timezones is removed.
  • The is\_dst argument is removed from:
    • QuerySet.datetimes()
    • django.utils.timezone.make\_aware()
    • django.db.models.functions.Trunc()
    • django.db.models.functions.TruncSecond()
    • django.db.models.functions.TruncMinute()
    • django.db.models.functions.TruncHour()
    • django.db.models.functions.TruncDay()
    • django.db.models.functions.TruncWeek()
    • django.db.models.functions.TruncMonth()
    • django.db.models.functions.TruncQuarter()
    • django.db.models.functions.TruncYear()
  • The django.contrib.gis.admin.GeoModelAdmin and OSMGeoAdmin classes
    are removed.
  • The undocumented BaseForm.\_html\_output() method is removed.
  • The ability to return a str, rather than a SafeString, when rendering
    an ErrorDict and ErrorList is removed.

See Features deprecated in 4.1 for details on these changes, including how
to remove usage of these features.

  • The SitemapIndexItem.\_\_str\_\_() method is removed.
  • The CSRF\_COOKIE\_MASKED transitional setting is removed.
  • The name argument of django.utils.functional.cached\_property() is
    removed.
  • The opclasses argument of
    django.contrib.postgres.constraints.ExclusionConstraint is removed.
  • The undocumented ability to pass errors=None to
    SimpleTestCase.assertFormError() and assertFormsetError() is removed.
  • django.contrib.sessions.serializers.PickleSerializer is removed.
  • The usage of QuerySet.iterator() on a queryset that prefetches related
    objects without providing the chunk\_size argument is no longer allowed.
  • Passing unsaved model instances to related filters is no longer allowed.
  • created=True is required in the signature of
    RemoteUserBackend.configure\_user() subclasses.
  • Support for logging out via GET requests in the
    django.contrib.auth.views.LogoutView and
    django.contrib.auth.views.logout\_then\_login() is removed.
  • The django.utils.timezone.utc alias to datetime.timezone.utc is
    removed.
  • Passing a response object and a form/formset name to
    SimpleTestCase.assertFormError() and assertFormSetError() is no
    longer allowed.
  • The django.contrib.gis.admin.OpenLayersWidget is removed.

  • The django.contrib.auth.hashers.CryptPasswordHasher is removed.

  • The "django/forms/default.html" and
    "django/forms/formsets/default.html" templates are removed.

  • The default form and formset rendering style is changed to the div-based.
  • Passing nulls\_first=False or nulls\_last=False to Expression.asc()
    and Expression.desc() methods, and the OrderBy expression is no
    longer allowed.

Details

date
Dec. 4, 2023, 1:08 p.m.
type
Major
👇
Register or login to:
  • 🔍View and search all Django releases.
  • 🛠️Create and share lists to track your tools.
  • 🚨Setup notifications for major, security, feature or patch updates.
  • 🚀Much more coming soon!
Continue with GitHub
Continue with Google
or