What a package declares
Link to this sectionTwo things a maintainer publishes about a package decide an upgrade:
Framework :: Django :: 5.2A classifier. It names a Django version the package supports.Django>=4.2,<6.1The Django requirement. It decides which versions the package installs with. An upper bound like this one excludes 6.1.
Together they give every Django version one of three states: declared, excluded or not declared. Only an exclusion blocks. Not declared means nobody has said anything. Usually a classifier is missing, sometimes nobody maintains the package any more.
What the 200 most downloaded Django packages declare
Link to this sectionTo see how that looks in practice, I checked the newest release of the 200 most downloaded Django packages against Django 5.2, 6.0 and 6.1 on 28 September 2026.
| Django | Declared | Not declared | Excluded |
|---|---|---|---|
| 5.2 LTS | 125 | 75 | 0 |
| 6.0 | 85 | 113 | 2 |
| 6.1 | 29 | 166 | 5 |
Downloads are those of the 30 days before 1 September 2026. The rules are those of django-upgrade-report 0.2.2, described in its README. Downloads are not installations, and the packages were selected by name, so a few Django packages with an unusual name are missing. The raw data is listed under sources.
Django 5.2 LTS: nothing excludes it
Not one of the 200 packages excludes 5.2. The 62 % that declare it account for 81 % of the downloads. If you are still on Django 4.2, the packages are not what stops you. They are a reason not to wait, though: for 30 of the 200, the newest release no longer installs on 4.2, among them Django REST framework, django-filter and django-debug-toolbar. Every month on 4.2 holds more packages back on old releases.
Django 6.1: mostly classifiers that lag behind
Django 6.1 came out on 5 August 2026. So far 29 packages declare it and 5 exclude it. 53 declare 6.0 but not yet 6.1, pytest-django, django-cors-headers and whitenoise among them. Of the 48 packages with a release since 5 August, half declare 6.1. That looks like lag, not like incompatibility.
The real blockers are few, but widely used
These five packages exclude 6.1 in their newest release. If you use one of them, you wait for a release, run a fork or replace it:
- django-celery-beat
Django<6.1, 7.6 million downloads a month - django-prometheus
Django<6.1, 4.2 million downloads a month - drf-extensions
Django<6.0, 2.4 million downloads a month - django-scim2
Django<6.1, 2.2 million downloads a month - django-postgres-extra
Django<6.0, 0.4 million downloads a month
The quiet risk: packages nobody maintains
37 of the 200 packages have had no release in more than two years. Every one of them is among the 75 that do not declare 5.2, django-model-utils with 4.9 million downloads a month, djangorestframework-csv and django-ratelimit among them. Such a package may keep working. If it breaks on the next version, though, nobody fixes it. Then the upgrade needs a replacement, and a replacement needs time.
The order matters as much as the answer
Link to this sectionA package that supports the target version has one of two places. If the release that declares the target still runs on your current Django, you update it first, on its own, and it goes live before Django changes. If that release has dropped your current Django, it has to come in the same change as Django.
And the newest release is often the wrong one. The newest django-debug-toolbar, 8.0, requires Django 5.2. On 4.2 the right step is 5.1.0, the oldest release that declares 5.2. Small steps like this keep every change easy to review.
This is what it looks like for an example project on Django 4.2.7 with 18 Django packages, planned for 5.2:
| Package | Today | Step | Note |
|---|---|---|---|
| django-crispy-forms | 2.0 | 2.4 | first, before crispy-bootstrap5 |
| crispy-bootstrap5 | 0.7 | 2025.4 | requires django-crispy-forms 2.3 or newer |
| django-allauth | 0.57.0 | 65.7.0 | requires Django 4.2.16 or newer: update Django 4.2 first |
| django-debug-toolbar | 4.2.0 | 5.1.0 | requires Django 4.2.9 or newer |
| django-storages | 1.14.2 | check by hand | newest release declares Django up to 5.1 |
| django-model-utils | 4.3.1 | check by hand | newest release declares Django up to 5.1, no release in two years |
In total: 15 packages to update before Django, 3 to check by hand, none blocked. Two of the updates need a newer patch release of Django 4.2, so the first step is an update within 4.2.
Check your own project
Link to this sectionI turned this check into a free, open-source tool: django-upgrade-report. It reads your lockfile or requirements, asks PyPI what every Django package declares and prints the plan: blocked, update first, update together with Django, check by hand, ready. In the project directory, one command is enough:
uvx django-upgrade-reportIt needs Python 3.10 or newer, but neither Django nor your virtualenv. Only package names and versions go to PyPI, never your code. Packages from git or a private index are not looked up at all. It also runs in CI, with Markdown, JSON or an HTML report.
django-upgrade-report on GitHub
It shows what maintainers declare, not whether your tests pass. Plan with it, then let django-upgrade rewrite the code and let the tests decide.