Django: what’s new in 6.0
Source: Hacker News
2025-12-03

Django 6.0 was released today, starting another release cycle for the loved and long‑lived Python web framework (now 20 years old!). It comes with a mosaic of new features, contributed to by many, some of which I am happy to have helped with. Below is my pick of highlights from the release notes.
Upgrade with help from django-upgrade
If you’re upgrading a project from Django 5.2 or earlier, try my tool django-upgrade. It automatically updates old Django code to use new features, fixing deprecation warnings, including five fixers for Django 6.0. (One day I’ll propose it to become an official Django project, when energy and time permit…)
Template partials
There are four headline features in Django 6.0, which we’ll cover before other notable changes, starting with this one:
The Django Template Language now supports template partials, making it easier to encapsulate and reuse small named fragments within a template file.
Partials are sections of a template marked by the new {% partialdef %} and {% endpartialdef %} tags. They can be reused within the same template or rendered in isolation.
Reuse partials within the same template
{% partialdef filter_controls %}
{{ filter_form }}
{% endpartialdef %}
{% partial filter_controls %}
{% for video in videos %}
## {{ video.title }}
...
{% endfor %}
{% partial filter_controls %}
You can simplify this pattern further with the inline option, which also renders the definition in place:
{% partialdef filter_controls inline %}
{{ filter_form }}
{% endpartialdef %}
{% for video in videos %}
## {{ video.title }}
...
{% endfor %}
{% partial filter_controls %}
Use this pattern any time you find yourself repeating template code within the same file. Because partials can use variables, they also help de‑duplicate similar controls with different data.
Render partials in isolation
{% load django_htmx %}
## {{ video.title }}
Your browser does not support the video tag.
{% partialdef view_count inline %}
{{ video.view_count }} views
{% endpartialdef %}
{% htmx_script %}
The corresponding view code:
from django.shortcuts import render
def video(request, video_id):
# …
return render(request, "video.html", {"video": video})
def video_view_count(request, video_id):
# …
return render(request, "video.html#view_count", {"video": video})
The video view renders the full template, while video_view_count renders only the view_count partial by appending #view_count to the template name—similar to referencing an HTML fragment by its ID in a URL.
History
htmx was the main motivation for this feature, as promoted by its creator Carson Gross in a cross‑framework review post. Using partials helps maintain “locality of behaviour” within templates, easing authoring, debugging, and maintenance by avoiding template file sprawl.
Django’s support for template partials was initially developed by Carlton Gibson in the django‑template‑partials package, which remains available for older Django versions. The integration into Django itself was done in a Google Summer of Code project this year, worked on by student Farhan Ali and mentored by Carlton, in Ticket #36410. You can read more about the development process in Farhan’s retrospective blog post. Many thanks to Farhan for authoring, Carlton for mentoring, and Natalia Bidart, Nick Pope, and Sarah Boyce for reviewing!
Tasks framework
The next headline feature:
Django now includes a built‑in Tasks framework for running code outside the HTTP request–response cycle. This enables offloading work, such as sending emails or processing data, to background workers.
Background tasks have long been a common requirement in web applications, but Django previously offered no built‑in solution, leading developers to rely on third‑party packages like Celery or Django Q2. The new Tasks framework provides a standard API for defining and enqueuing background tasks, allowing third‑party task runners to integrate uniformly.
Define tasks with the new @task decorator:
from django.tasks import task
@task
def resize_video(video_id):
...
Enqueue them for background execution with Task.enqueue():
from example.tasks import resize_video
def upload_video(request):
# …
resize_video.enqueue(video.id)
# …
Execute tasks
At this time, Django does not include a production‑ready task backend. Two backends are provided for development and testing: