Was ein Sprung mit den Paketen macht

Link zu diesem Abschnitt

Die 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.

Beispielprojekt mit 14 Django-Paketen: wo jedes Update landet
WegVor DjangoZusammen mit DjangoVon Hand prüfenBereit
3.2 auf 5.2 in einem Sprung2930
Schritt 1: 3.2 auf 4.211300
Schritt 2: 4.2 auf 5.210031

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.

Vier der 14 Pakete auf dem Weg über 4.2
PaketHeuteSchritt 1Schritt 2
djangorestframework3.14.03.15.03.16.0
django-filter22.123.125.1
django-allauth0.52.00.55.065.7.0
django-crispy-forms1.14.02.1, mit Django2.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 Abschnitt

Django 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 test

Wo die Pakete stehen: bei den LTS-Versionen

Link zu diesem Abschnitt

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

Screenshot der Seite How ready is the Django ecosystem: oben drei Kennzahlen (168 von 300 Paketen deklarieren Django 5.2 LTS, 42 deklarieren Django 6.1, 7 blockieren es), der Befehl für das eigene Projekt und ein Diagramm mit einer Linie pro Django-Version, das den Anteil der Pakete zeigt, die sie nach Tagen seit dem Release deklariert haben. (öffnet neuen Tab)
Die Seite am 10. Oktober 2026. Das Diagramm zeigt für jede Django-Version, wie schnell die Pakete nach dem Release nachgezogen haben.
Neueste Version der 300 meistgeladenen Django-Pakete, Stand 10. Oktober 2026
DjangoBereitZu prüfenBlockiertDeklariert nach 1 Jahr
4.2 LTS1481094349 %
5.01041534344 %
5.11111533644 %
5.2 LTS168131151 %
6.01161804zu neu
6.1422517zu 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 Abschnitt

Jede LTS-Version legt auch fest, auf welchem Python und welchem PostgreSQL sie läuft:

Worauf die drei LTS-Versionen laufen
DjangoPythonPostgreSQLSicherheitsupdates bis
3.2 LTS3.6 bis 3.10ab 9.61. April 2024
4.2 LTS3.8 bis 3.12ab 127. April 2026
5.2 LTS3.10 bis 3.14ab 14April 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 Abschnitt

Für das Beispielprojekt sieht der ganze Weg so aus. Jeder Schritt geht einzeln live und hat einen Weg zurück.

  1. Django 3.2 auf die letzte Patch-Version, 3.2.25. Tests mit eingeschalteten Warnungen laufen lassen und jede Deprecation-Warnung beheben.
  2. Die 11 Pakete aktualisieren, deren nächste Version noch auf 3.2 läuft, eines nach dem anderen.
  3. Django 4.2, in einer Änderung mit den drei Paketen, die es brauchen.
  4. Python 3.12 auf Django 4.2, nach Pillow und psycopg2-binary. Dann die Deprecation-Warnungen beheben, die 4.2 ausgibt.
  5. 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.
  6. 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 Abschnitt

Beide 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 lts

Es 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.