Upgrade Django 4.2 to 5.2 LTS: A Step-by-Step Checklist

Django 4.2 is out of support. Upgrade Django 4.2 to 5.2 LTS step by step: deprecation warnings, removed settings, STORAGES, USE_TZ, Python and package checks.

lighter staircase with railings
Photo by Alessia Cocconi / Unsplash

To upgrade Django 4.2 to 5.2, go in steps rather than one jump. Fix every deprecation warning on 4.2, then move to 5.0, 5.1 and 5.2, running the full test suite at each stop. Get onto Python 3.10 or newer, replace removed settings such as DEFAULT_FILE_STORAGE, set USE_TZ explicitly, and update packages first.

TL;DR: Django 4.2 lost security support on April 7, 2026, and 5.2 LTS is supported until April 2028. Turn on deprecation warnings and clear them on 4.2, move one feature release at a time, switch to the STORAGES setting, decide USE_TZ on purpose, and check every third-party package before each step. Plan the rollback before each deploy.

This is a checklist built from Django's own release notes, deprecation timeline and upgrade guide, checked on October 21, 2026. It isn't a war story from one project. It's the order of work we follow on any Django codebase, written down so you can run it yourself or hand it to whoever does.

Is Django 4.2 still supported?

No. Django's supported versions table lists 4.2 LTS as unsupported, with extended support having ended on April 7, 2026. An app on 4.2 no longer gets security fixes. Django 5.2 is an LTS release with extended support until April 2028, which makes it the natural next stop.

The Django 5.2 release notes say it will receive security updates for at least three years after release. That's the reason to aim for an LTS: you upgrade once and then get a long stretch of security and data loss fixes without chasing every feature release.

Why go to 5.2 and not straight to 6.x?

Django 6.0 and 6.1 are both out, but neither is an LTS. According to the download page, 6.0's extended support ends in April 2027 and 6.1's in December 2027, both earlier than 5.2's April 2028. So a 4.2 app that moves to 6.1 today gets a shorter supported window than one that stops at 5.2.

There's a timing question too. The same page lists Django 6.2 LTS for April 2027, with extended support to April 2030. If you're on 4.2 now, the calm plan is 5.2 today and 6.2 once it has had a patch release or two. Django's release process also changes after 6.2: from the release it calls Django 2028, every feature release gets three years of fixes and there are no separate LTS releases.

Need something only 6.x offers? Same method, more steps.

How do you upgrade Django 4.2 to 5.2 safely?

Follow Django's upgrade guide: clear deprecation warnings on your current version, then move through each feature release using its latest patch release, running the test suite with warnings on at every step. In practice that's five steps:

  1. Read the release notes for 5.0, 5.1 and 5.2. Focus on "Backwards incompatible changes" and "Features removed".
  2. Turn on deprecation warnings on 4.2 and fix them all. Python hides them by default. Run python -Wa manage.py test, or with pytest, PYTHONWARNINGS=always pytest tests --capture=no so output isn't captured.
  3. Update third-party packages to versions that support the next Django release.
  4. Move one feature release at a time: 4.2 to 5.0, then 5.1, then 5.2, each on its latest patch. Test and deploy to staging at each step.
  5. Deploy, then clear the cache if you use Django's cache framework. The guide notes pickled objects aren't guaranteed to survive a version change.

Incremental sounds slower. It's faster, because each step breaks only a few things and the cause is obvious.

One practical note on warnings runs: the first pass is noisy, and much of the noise comes from third-party packages. The guide itself says those warnings don't necessarily mean a problem, since a package may support several Django versions at once. Sort warnings by origin and fix your own code first.

Which changes break most often between 4.2 and 5.2?

Most of what bites was deprecated in 4.2 or earlier and removed in 5.0 or 5.1, per Django's deprecation timeline. The useful part is the middle column: if it was deprecated on 4.2, you can fix it while still on 4.2, where the old and new ways both work.

Change Deprecated in Removed or changed in What to do
Python 3.10 or newer required n/a 5.0 Upgrade Python first, in its own deploy
USE_TZ default becomes True 4.0 5.0 Set it explicitly in settings
DEFAULT_FILE_STORAGE and STATICFILES_STORAGE 4.2 5.1 Move to STORAGES
Meta.index_together 4.2 5.1 Replace with Meta.indexes, migrate on 4.2
length_is template filter 4.2 5.1 Use length with a comparison
TransactionTestCase.assertQuerysetEqual() 4.2 5.1 Use assertQuerySetEqual()
SimpleTestCase.assertFormsetError() 4.2 5.1 Use assertFormSetError()
SHA1, unsalted SHA1 and unsalted MD5 hashers 4.2 5.1 Remove them from PASSWORD_HASHERS
Third-party packages n/a Every step Check each one's supported versions

The 5.0 release notes confirm the Python floor (3.10, 3.11 and 3.12) and the USE_TZ default. The 5.1 release notes list every 5.1 removal above.

Why does USE_TZ deserve its own deploy?

Because switching it changes how every datetime is stored and compared. New projects from startproject have shipped with USE_TZ = True in settings for several releases, but older projects, or ones whose settings were copied by hand, may never have set it. On 5.0 the default became True, so an unset project suddenly works with aware datetimes.

Set USE_TZ explicitly before you upgrade. If you need to go from False to True, treat it as a data change, not a settings tweak: existing naive datetimes in the database need a decision about which time zone they were written in. Ship it on its own, with tests on reports, exports and anything that groups by date. Have you checked what "today" means in your daily sales report?

How do you move file storage to the STORAGES setting?

Replace the two removed settings with one dictionary while you're still on 4.2, where both forms work. STORAGES has a default key for media files and a staticfiles key for static assets, each naming a backend. Per the settings reference, defining it overrides the default value rather than merging with it.

# settings.py, Django 4.2 and later
STORAGES = {
    "default": {
        "BACKEND": "storages.backends.s3.S3Storage",  # your media backend
        "OPTIONS": {"bucket_name": "my-media"},
    },
    "staticfiles": {
        "BACKEND": "django.contrib.staticfiles.storage.ManifestStaticFilesStorage",
    },
}

Because the setting isn't merged, define both keys even if you only change one. If you use a storage package for S3, Google Cloud Storage or similar, upgrade the package first and check its docs for the exact backend path and options.

Why are third-party packages usually the slow part?

Your own code is rarely what holds an upgrade up. Packages are, especially unmaintained ones. Before you start:

  1. List every Django-related package and its pinned version.
  2. Check each changelog for the Django versions it supports.
  3. Flag anything unmaintained. Replace or fork it before the upgrade, not during it.

For APIs built on Django REST Framework, as SigmaCPM is, check DRF's supported Django versions alongside your auth, filtering and schema packages. How SigmaCPM's DRF code is laid out is covered in Django REST Framework for a multi-product platform.

What do you get once you're on 5.2?

Not only security fixes. A few 5.x features are worth using once you've landed:

  • db_default for database-computed defaults and GeneratedField for generated columns, both new in 5.0.
  • LoginRequiredMiddleware in 5.1, which makes login the default for every view, with login_not_required() for public ones.
  • CompositePrimaryKey in 5.2, useful for tenant-scoped join tables.
  • Automatic model imports in manage.py shell in 5.2, a small daily convenience.

What should be tested and planned before you start?

If the test suite is thin, any method is risky. Add tests first around login, signup and password reset; checkout, invoices and subscriptions; permissions, especially anything multi-tenant; date-based reports and exports; and file uploads. They don't need to be elegant. They need to fail loudly when behavior changes.

Then plan the rollback for every step before it ships. Take a database backup and confirm you can restore it. Check which migrations Django and your packages add, and whether they reverse. Deploy the version bump on its own, with no feature work, so rolling back removes nothing else. Watch errors and slow queries for a day before the next step. If something misbehaves, roll back code first and restore data only when a migration changed something you can't reverse.

How long does the whole thing take? A small, well-tested app with few packages can usually move in days. A large one with old packages, missing tests and custom storage can take weeks. The honest way to know is a short audit: list the packages, run with warnings on, and count what breaks. The time nearly always goes on package gaps and date assumptions, not on Django's own changes.

FAQ

Do we need to change our database before upgrading to Django 5.2?

Possibly. Each feature release sets its own minimum database versions, so check the "Backwards incompatible changes" section of the 5.0, 5.1 and 5.2 release notes for your backend. If your managed Postgres or MySQL is older than the floor, upgrade the database server first, as a separate change with its own backup.

Should we wait for Django 6.2 LTS instead of moving to 5.2?

Not if you're on 4.2, which already gets no security fixes. Move to 5.2 now; its support runs to April 2028. Django lists 6.2 LTS for April 2027, which leaves a comfortable year to plan the next LTS-to-LTS move with the same step-by-step method.

Can we skip fixing deprecation warnings and just fix what breaks?

You can, but you lose the safest window. Most removals in 5.0 and 5.1 were deprecated on 4.0 or 4.2, where the old and new ways both work. Fixing warnings there lets you ship each change on its own and test it, instead of meeting all of them at once.

Does upgrading Django mean upgrading Python as well?

Yes, if you're below 3.10, because Django 5.0 and later need Python 3.10 or newer. Do the Python upgrade first, still on Django 4.2, in its own deploy. Then a failure clearly belongs to one change, and you aren't debugging the interpreter and the framework at the same time.

Running an old Django version? Hire a Django developer for an upgrade audit with a written step plan, or read about our Django development work and compare stacks on the Django vs Node.js page.