Was ein Sprung mit den Paketen macht
Link zu diesem AbschnittDie meiste Arbeit eines Upgrades steckt in den Paketen, und ihre Reihenfolge entscheidet über das Risiko. Ein Update, das noch auf deinem jetzigen Django läuft, geht einzeln live, bevor sich Django ändert. Eines, das dein jetziges Django fallen gelassen hat, muss in derselben Änderung kommen wie Django.
Für ein Beispielprojekt habe ich beide Wege geplant: Django 3.2.18 auf Python 3.9 mit 14 Django-Paketen, Ziel 5.2.
| Weg | Vor Django | Zusammen mit Django | Von Hand prüfen | Bereit |
|---|---|---|---|---|
| 3.2 auf 5.2 in einem Sprung | 2 | 9 | 3 | 0 |
| Schritt 1: 3.2 auf 4.2 | 11 | 3 | 0 | 0 |
| Schritt 2: 4.2 auf 5.2 | 10 | 0 | 3 | 1 |
Beim Sprung wechseln neun Pakete im selben Deploy wie Django selbst, darunter django-allauth über 13 Major-Versionen. Bricht danach etwas, haben sich zehn Dinge zugleich geändert. Über 4.2 wechseln im ersten Schritt drei Pakete mit Django und im zweiten keines. Alles andere geht einzeln live.
| Paket | Heute | Schritt 1 | Schritt 2 |
|---|---|---|---|
| djangorestframework | 3.14.0 | 3.15.0 | 3.16.0 |
| django-filter | 22.1 | 23.1 | 25.1 |
| django-allauth | 0.52.0 | 0.55.0 | 65.7.0 |
| django-crispy-forms | 1.14.0 | 2.1, mit Django | 2.4 |
Drei Pakete brauchen auf beiden Wegen einen Blick: django-model-utils, django-storages und django-taggit deklarieren 5.2 in ihrer neuesten Version nicht.
Beide Pläne stammen von django-upgrade-report 1.1.0, gerechnet am 10. Oktober 2026. Das Projekt ist ausgedacht, aber typisch. Seine Requirements und die vollständigen Pläne stehen bei den Quellen.
Warum die Warnungen nur eine LTS-Version weit reichen
Link zu diesem AbschnittDjango entfernt eine Funktion in zwei Stufen. Zuerst kommt eine Deprecation-Warnung, zwei Feature-Versionen später ist die Funktion weg. Auf einer LTS-Version siehst du deshalb eine Warnung für alles, was die Versionen bis zur nächsten LTS entfernen. Behebst du die Warnungen auf 3.2, sind die 37 Funktionen, die 4.0 und 4.1 entfernen, erledigt, bevor sich die Version ändert.
Weiter reicht das nicht. Die 43 Funktionen, die 5.0 und 5.1 entfernen, wurden in den 4.x-Versionen als veraltet markiert. Django 3.2 kennt sie nicht und warnt vor keiner. Ein Sprung von 3.2 auf 5.2 trifft sie als Fehler, in der Reihenfolge, in der die Tests darauf stoßen. Auf 4.2 sind dieselben 43 Warnungen, die die Zeile nennen, aus der sie kommen.
Die Upgrade-Anleitung von Django geht noch einen Schritt feiner und empfiehlt jede Feature-Version der Reihe nach, jeweils auf ihrer neuesten Patch-Version. Ein gangbarer Mittelweg: Die Versionen dazwischen laufen in CI, die LTS-Versionen gehen live. Die Warnungen sind standardmäßig stumm. Für den Testlauf schaltest du sie ein:
python -Wa manage.py testWo die Pakete stehen: bei den LTS-Versionen
Link zu diesem AbschnittEin Beispielprojekt beweist wenig. Dieselbe Prüfung veröffentliche ich deshalb für das ganze Ökosystem, jede Woche: die neueste Version der 300 meistgeladenen Django-Pakete auf PyPI, geprüft gegen jede Django-Version ab 4.2.
Django ecosystem readiness, jeden Montag aktualisiert (öffnet neuen Tab)

| Django | Bereit | Zu prüfen | Blockiert | Deklariert nach 1 Jahr |
|---|---|---|---|---|
| 4.2 LTS | 148 | 109 | 43 | 49 % |
| 5.0 | 104 | 153 | 43 | 44 % |
| 5.1 | 111 | 153 | 36 | 44 % |
| 5.2 LTS | 168 | 131 | 1 | 51 % |
| 6.0 | 116 | 180 | 4 | zu neu |
| 6.1 | 42 | 251 | 7 | zu neu |
Zwei Dinge fallen auf. Bei den LTS-Versionen stehen heute die Pakete: 168 sind bereit für 5.2 und 148 für 4.2, bei 5.0 sind es 104 und bei 5.1 111. Nach Downloads gezählt ist der Abstand größer: Die Pakete, die für 5.2 bereit sind, stehen für 79 % der Downloads, die für 5.0 für 37 %. Im ersten Jahr nach einem Release ist der Vorsprung klein: 51 % der Pakete haben 5.2 innerhalb eines Jahres deklariert und 49 % 4.2, bei 5.0 und 5.1 je 44 %. Ein Plan, der bei den LTS-Versionen hält, hält dort, wo die Pakete sind.
Das zweite: Die Unterstützung für alte Versionen verschwindet. Bei 43 der 300 Pakete schließt die neueste Version Django 4.2 aus, nur bei einem 5.2. Deshalb nennt jeder Schritt eines Plans die älteste Version, die das Ziel deklariert, und nicht die neueste. Die älteren Versionen bleiben auf PyPI, der Weg über 4.2 bleibt also offen. Korrekturen bekommen sie keine mehr. Auch deshalb sollte dieser Halt kurz sein.
Neue Versionen starten langsam. Django 6.1 ist am 5. August 2026 erschienen. Nach 60 Tagen hatten 13 % der Pakete eine Version, die es deklariert.
Bereit heißt, die neueste Version deklariert die Django-Version. Zu prüfen heißt, die Metadaten sagen nichts dazu, und das ist nicht dasselbe wie inkompatibel. Blockiert heißt, sie schließt die Version aus. Der Anteil nach einem Jahr zählt jedes Paket mit einer Version, die die Django-Version bis dahin deklariert hat, auch wenn die neueste sie inzwischen fallen gelassen hat. Die Pakete wurden nach ihrem Namen ausgewählt, und Downloads sind keine Installationen.
Python und die Datenbank wechseln mit
Link zu diesem AbschnittJede LTS-Version legt auch fest, auf welchem Python und welchem PostgreSQL sie läuft:
| Django | Python | PostgreSQL | Sicherheitsupdates bis |
|---|---|---|---|
| 3.2 LTS | 3.6 bis 3.10 | ab 9.6 | 1. April 2024 |
| 4.2 LTS | 3.8 bis 3.12 | ab 12 | 7. April 2026 |
| 5.2 LTS | 3.10 bis 3.14 | ab 14 | April 2028 |
Django 3.2 und 5.2 teilen sich genau eine Python-Version, 3.10, und Python 3.10 hat im Oktober 2026 selbst sein Supportende erreicht. Ein direkter Sprung passiert also auf Python 3.10, oder er ändert Python und Django im selben Schritt. Django 4.2 läuft auf 3.8 bis 3.12. Dort wechselst du Python, während Django stillsteht.
Im Beispielprojekt brauchen zwei Pakete eine neuere Version, bevor sie auf Python 3.12 laufen: Pillow und psycopg2-binary. Für die installierten Versionen gibt es dafür kein Wheel. Beide Updates gehen vor dem Wechsel live.
Der Weg in sechs Schritten
Link zu diesem AbschnittFür das Beispielprojekt sieht der ganze Weg so aus. Jeder Schritt geht einzeln live und hat einen Weg zurück.
- Django 3.2 auf die letzte Patch-Version, 3.2.25. Tests mit eingeschalteten Warnungen laufen lassen und jede Deprecation-Warnung beheben.
- Die 11 Pakete aktualisieren, deren nächste Version noch auf 3.2 läuft, eines nach dem anderen.
- Django 4.2, in einer Änderung mit den drei Paketen, die es brauchen.
- Python 3.12 auf Django 4.2, nach Pillow und psycopg2-binary. Dann die Deprecation-Warnungen beheben, die 4.2 ausgibt.
- Die 10 Pakete aktualisieren, deren nächste Version noch auf 4.2 läuft. Bei den dreien, die 5.2 nicht deklarieren, den Changelog lesen.
- Django 5.2, für sich allein.
Das sind mehr Deploys als bei einem Sprung. Jeder ändert eine Sache, ein Fehler zeigt also auf seine Ursache. Ist dein PostgreSQL älter als 14, kommt dessen Upgrade als weiterer Schritt vor dem letzten.
Den Weg für dein eigenes Projekt planen
Link zu diesem AbschnittBeide Pläne oben stammen von django-upgrade-report, einem kostenlosen Open-Source-Werkzeug, das ich pflege. Seit Version 1.0 plant es den ganzen Weg statt eines einzelnen Schritts. Im Projektverzeichnis:
uvx django-upgrade-report --target 5.2 --via ltsEs liest dein Lockfile oder deine Requirements und gibt einen Plan pro LTS-Version auf dem Weg aus, jeder beginnt dort, wo der vorige endet. Es listet, was Django unterwegs entfernt hat und wo dein Code es noch verwendet, und sagt, was deine Abhängigkeiten auf dem neuen Python brauchen. Mit --emit gibt es die Befehle in der richtigen Reihenfolge aus, für uv, Poetry, PDM, Pipenv oder pip.
Es braucht Python 3.10 oder neuer, aber weder Django noch dein Virtualenv. Dein Code wird lokal gelesen und nie gesendet. An PyPI gehen nur Namen und Versionen von Paketen, die von PyPI kommen.
django-upgrade-report auf GitHub (öffnet neuen Tab)
Der Plan zeigt, was die Maintainer erklären, nicht, ob deine Tests grün sind. Damit planst du. Den Code schreibt danach django-upgrade um, und die Tests entscheiden.