Django 5.0 LTS (2023-12-04)

Deprecation policy

Django 5.0 (the version that follows 4.2) will still contain the backwards-compatible replica.

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.

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.

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())

More options for declaring field choices

Now Django 5.0 supports choices as a mapping!

This feature was requested 4 years ago (#31262) and we can’t wait to use it! Thank you to Tom Forbes, Nick Pope and Natalia Bidart for their work getting this in 💜

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 Winners(models.Model):
    name = models.CharField(...)
    medal = models.CharField(..., choices=Medal.choices)
    sport = models.CharField(..., choices=SPORT_CHOICES)

Django 5.0 supports providing a mapping 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",
}


class Winners(models.Model):
    name = models.CharField(...)
    medal = models.CharField(..., choices=Medal)  # Using `.choices` not required.
    sport = models.CharField(..., choices=SPORT_CHOICES)

Under the hood the provided choices are normalized into a list of 2-tuples as the canonical form whenever the choices value is updated

Videos