Skip to content

Django 4.2 → 5.2 LTS upgrade (spike — DO NOT MERGE without Raymond + Eric review) (#1081) - #1203

Draft
rdhyee wants to merge 2 commits into
masterfrom
django52-spike
Draft

Django 4.2 → 5.2 LTS upgrade (spike — DO NOT MERGE without Raymond + Eric review) (#1081)#1203
rdhyee wants to merge 2 commits into
masterfrom
django52-spike

Conversation

@rdhyee

@rdhyee rdhyee commented Jul 3, 2026

Copy link
Copy Markdown
Member

DRAFT — gated on Raymond AND Eric. Deliverable of the 5.2 spike (#1081). Full results + go/no-go analysis: UPGRADE_PLAN_5.2.md (Gluejar dir).

Headline

Executed the upgrade for real against the full test suite: 3 dependency bumps + a handful of small code fixes → Django 5.2.15 runs with ZERO new test failures vs the 4.2 baseline (identical 12-item failure set, all pre-existing/environmental). Everything the paper plan feared — vendored forks, django-selectable, django-registration — works unchanged.

Changes

  • Deps: django → 5.2.15; django-sass-processor 0.8.2→1.4.2 (get_storage_class removed in 5.1); django-mptt 0.14→0.18 (index_together removed in 5.1); django-contrib-comments 2.0→2.2 (5.x migration-state drift).
  • USE_TZ = False pinned — Django 5.0 flipped the default; regluit + its production data are naive-datetime. Preserves current behavior exactly; TZ-aware migration is a separate future project.
  • Real bug fix — Campaign.clone(): filtered Transactions on an unsaved instance (pk=None); silent no-match on ≤4.2, hard error on 5.x. save() now precedes update_left() (identical semantics).
  • Test fixes: assertRegexpMatchesassertRegex (removed in Python 3.12 — was already broken on prod's Python); Django 5.0 signal receivers are 3-tuples.
  • Includes the #1202 STORAGES/USE_L10N prep (cherry-picked; land that PR first).

Verification (local, Docker MySQL 8 utf8mb3 + redis 7, Python 3.12.9)

  • pip install with 5.2: zero conflicts.
  • manage.py check: clean (only the known ckeditor.W001).
  • makemigrations --check: clean. migrate over a 4.2 schema: applies only django_comments.0004 (an index).
  • Full suite 4.2 vs 5.2: identical failure sets (12 pre-existing environmental failures both sides; celery tests pass both sides).
  • Django 6.0 deprecation scan: mild (URLField scheme default; utcnow() — folds into the TZ project).

Before merge

  1. Land Django 5.2 prep: STORAGES dict + drop USE_L10N (#1081) #1202. 2. Raymond + Eric review. 3. Deploy to test.unglue.it with -e run_pip=true and run the smoke gate (RUNBOOK_deploy_test_then_prod.md). 4. Soak, then release per runbook.

rdhyee and others added 2 commits July 3, 2026 11:11
Forward-compatible settings changes that behave identically on the current
Django 4.2 runtime and unblock the 5.2 upgrade:

- Replace DEFAULT_FILE_STORAGE (removed in Django 5.1) with the STORAGES dict.
  STORAGES has been supported since Django 4.2, so this is a no-op on the live
  runtime; the S3 (django-storages) vs FileSystemStorage selection is preserved.
- Remove USE_L10N (removed in Django 5.0; localized formatting is always on).

The other 5.0/5.1 landmines from the plan are already clean in this codebase
(no `django.utils.timezone.utc`, no `index_together`, no removed util imports).

Refs #1081. NOTE: the STORAGES change touches the prod S3 media path — validate
media upload/serve on test.unglue.it before merge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fm18PoiZmSo2iJGWHuVNm4
Dependency bumps (the only three that block 5.2 at import/check time):
- django-sass-processor 0.8.2 -> 1.4.2 (get_storage_class removed in 5.1)
- django-mptt 0.14.0 -> 0.18.0 (Meta.index_together removed in 5.1)
- django-contrib-comments 2.0.0 -> 2.2.0 (migration-state drift under 5.x)
- django 4.2.21 -> 5.2.15 (LTS, supported to April 2028)

Code changes:
- settings/common.py: pin USE_TZ = False. Django 5.0 flipped the default to
  True; this codebase and the production data are naive-datetime throughout.
  Preserves existing behavior; the TZ-aware migration is a separate project.
- core/models/__init__.py Campaign.clone(): save() before update_left().
  update_left() filters Transactions on the instance, and Django 5.x raises
  ValueError for unsaved instances in related filters (4.2 silently matched
  nothing). Identical semantics: a fresh clone has no transactions.
- libraryauth/tests.py: signal receivers are 3-tuples in Django 5.0+.
- booxtream/core tests: assertRegexpMatches -> assertRegex (removed in
  Python 3.12; pre-existing breakage independent of Django).

Verified: manage.py check clean; makemigrations --check clean; migrate over a
4.2-schema DB applies only django_comments 0004; full test suite failure set
IDENTICAL to the 4.2 baseline (zero new failures on 5.2).

Refs #1081. Builds on the STORAGES/USE_L10N prep (#1202, cherry-picked).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Fm18PoiZmSo2iJGWHuVNm4
@rdhyee

rdhyee commented Jul 3, 2026

Copy link
Copy Markdown
Member Author

Codex review: LGTM (no high-confidence blockers). Notable points, all captured:

@rdhyee rdhyee added the CC+Codex+LGTM Authored by Claude Code and reviewed by Codex; both approved (LGTM). Awaiting human review/merge. label Jul 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CC+Codex+LGTM Authored by Claude Code and reviewed by Codex; both approved (LGTM). Awaiting human review/merge.

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

1 participant