Skip to content

Update Django to 5.2 - #3768

Open
mbertrand wants to merge 7 commits into
mainfrom
mb/django-5-upgrade
Open

Update Django to 5.2#3768
mbertrand wants to merge 7 commits into
mainfrom
mb/django-5-upgrade

Conversation

@mbertrand

@mbertrand mbertrand commented Aug 13, 2026

Copy link
Copy Markdown
Member

What are the relevant tickets?

Replaces #3742.

Description (What does it do?)

Updates Django 4.2.30 to 5.2.16. and makes other changes required to fix the failing unit tests in #3742

The biggest change worth a close look is in ApisixUserMiddleware. Django 5 gives RemoteUserMiddleware its own __call__ that ignores whatever process_request returns, so our return self.get_response(request) meant every request ran the rest of the middleware chain and the view a second time. Returning None fixes it and behaves the same on 4.2. Same fix I made in learn-ai (https://github.com/mitodl/learn-ai#423).

The rest:

  • index_together was removed in 5.1, so ChannelGroupRole uses Meta.indexes. The migration renames the existing index instead of rebuilding it.
  • USE_L10N was removed in 5.0.
  • django-filter was pinned >=2.4.0,<3, which resolves to 2.4.0 from 2020. It calls ChoiceField._set_choices, which Django 5.0 removed — 138 test failures on its own. The pin could never have reached a fix because django-filter moved to CalVer (21.1 through 26.1), so the upper bound is gone and uv.lock is the pin.
  • djangorestframework 3.17.2 fixes a RawPostDataException when DRF reads request.data.
  • django-safedelete still calls the deprecated log_action(), so that warning is ignored until upstream switches to log_actions().
  • Django 5.2 needs PostgreSQL 14+. CI was still on 12.22 so it's bumped to 16, matching what docker-compose already runs locally.
  • renovate.json capped Django at <5, which is why we stayed on 4.2 through its EOL. Raised to <6 so 5.2.x patches come through without 6.x landing on its own.

How can this be tested?

  • docker compose build --no-cache web celery
  • Smoke test the site — log in, log out, log back in, browse, search, update favorites and/or learning paths.

Unit tests should all pass.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

OpenAPI Changes

No changes detected

View full changelog

Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

@mbertrand
mbertrand force-pushed the mb/django-5-upgrade branch from 41bf855 to 9d79dda Compare August 13, 2026 14:14
@mbertrand mbertrand added the Needs Review An open Pull Request that is ready for review label Aug 13, 2026
@mbertrand
mbertrand marked this pull request as ready for review August 13, 2026 15:23
Copilot AI balanced review requested due to automatic review settings August 13, 2026 15:23

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Upgrades the Django backend to 5.2.16 and updates related dependencies and compatibility code.

Changes:

  • Updates Django, django-filter, DRF, PostgreSQL CI, and Renovate constraints.
  • Adapts APISIX middleware and settings for Django 5.2.
  • Migrates the deprecated channel index configuration.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
uv.lock Locks upgraded dependencies.
renovate.json Allows Django 5.x updates.
pyproject.toml Updates dependency constraints.
main/settings.py Removes obsolete localization setting.
main/middleware/apisix_user.py Adapts middleware response handling.
main/middleware/apisix_user_test.py Updates middleware invocation coverage.
fixtures/common.py Suppresses an upstream deprecation warning.
channels/models.py Replaces deprecated index configuration.
channels/migrations/0017_channelgrouprole_index.py Renames the existing database index.
.github/workflows/ci.yml Upgrades CI PostgreSQL to version 16.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread main/middleware/apisix_user.py
Comment thread main/middleware/apisix_user.py

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated no new comments.

Suppressed comments (1)

fixtures/common.py:59

  • Scope this suppression to django-safedelete. Because the filter currently matches only the warning text, any future first-party call to LogEntryManager.log_action() will also be silently ignored, defeating this fixture's warnings-as-errors check. Django emits this warning with stacklevel=2, so the reported module for the known third-party call is safedelete.admin.
        warnings.filterwarnings(
            "ignore",
            message=r"LogEntryManager\.log_action\(\) is deprecated.*",
            category=DeprecationWarning,
        )

renovate Bot and others added 5 commits August 13, 2026 12:49
Django 5 gives RemoteUserMiddleware its own __call__ that discards the
return value of process_request, so ApisixUserMiddleware returning
self.get_response(request) made every request run its downstream chain
twice — doubled writes, doubled side effects, throttle limits consumed at
2x. Returning None and letting __call__ drive the chain fixes it, and
behaves identically on 4.2. Same fix as learn-ai 2fe143b.

The rest:

- index_together was removed in 5.1; Meta.indexes replaces it and the
  migration renames the existing index in place rather than rebuilding it
- USE_L10N was removed in 5.0
- django-filter 2.4.0 calls ChoiceField._set_choices, which 5.0 removed.
  The >=2.4.0,<3 pin could never reach a fixed release because upstream
  switched to CalVer (21.1 ... 26.1), so the upper bound comes off
- djangorestframework 3.17.2 fixes RawPostDataException when DRF reads
  request.data under 5.2
- django-safedelete 1.4.1 still calls the deprecated log_action(); ignore
  the warning until upstream moves to log_actions()
- renovate was capped at Django <5, which is why 4.2 sat here through its
  EOL; raise it to <6 so 5.2.x patches come through

Full suite passes apart from the ordering flakes tracked in mitodl/hq#12841.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Django 5.2 requires PostgreSQL 14+. CI was still on 12.22; local dev
already runs 16 via docker-compose.services.yml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Matches taskbatch_job_status_idx and content_fb_course_time_idx rather
than Django's auto-generated hash name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The same_user case called process_request() directly, so it couldn't catch
the duplicate get_response() run this branch fixes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@mbertrand
mbertrand force-pushed the mb/django-5-upgrade branch from 9605cdf to c2967d7 Compare August 13, 2026 16:50
mbertrand and others added 2 commits August 13, 2026 12:54
Matching on message alone would also swallow the warning for any
first-party log_action() call.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Needs Review An open Pull Request that is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants