Skip to content

chore: upgrade Django 4.2 β†’ 5.2#9325

Open
sriramveeraghanta wants to merge 1 commit into
previewfrom
chore/django-5.2-upgrade
Open

chore: upgrade Django 4.2 β†’ 5.2#9325
sriramveeraghanta wants to merge 1 commit into
previewfrom
chore/django-5.2-upgrade

Conversation

@sriramveeraghanta

@sriramveeraghanta sriramveeraghanta commented Jun 26, 2026

Copy link
Copy Markdown
Member

Description

Upgrades the API backend (apps/api, the only Django service in the monorepo) from Django 4.2.30 LTS to 5.2.15 LTS, with all Django-coupled dependencies bumped to versions that officially support 5.2.

An end-to-end audit (12 breaking-change scans + settings audit + 129-migration scan + per-dependency compatibility checks) found the application code already 5.2-clean, so this is primarily a coordinated dependency bump plus the few touch-points the upgrade required. No runtime/infra blockers: Python 3.12 (β‰₯3.10 βœ“), Postgres 15.7 (β‰₯14 βœ“), psycopg 3 βœ“.

Dependency bumps (requirements/):

  • Django 4.2.30 β†’ 5.2.15; DRF 3.15.2 β†’ 3.17.1; channels 4.1.0 β†’ 4.3.2; django-cors-headers 4.3.1 β†’ 4.9.0; django-filter 24.2 β†’ 25.2; django-storages 1.14.2 β†’ 1.14.6; django-redis 5.4.0 β†’ 7.0.0; celery 5.4.0 β†’ 5.5.3; django-celery-beat 2.6.0 β†’ 2.9.0; django-celery-results 2.5.1 β†’ 2.6.0; drf-spectacular 0.28.0 β†’ 0.29.0; scout-apm 3.1.0 β†’ 3.5.3; psycopg (+binary/+c) 3.3.0 β†’ 3.3.4; whitenoise 6.11.0 β†’ 6.12.0; django-debug-toolbar 4.3.0 β†’ 6.0.0 (dev); pytest-django 4.5.2 β†’ 4.12.0 (test).
  • OpenTelemetry set, django-crum, and pytz intentionally held (already 5.2-compatible; bumping adds churn with no 5.2 benefit). debug-toolbar pinned to 6.0 (not 7.0, which drops Django 4.2) and celery to 5.5.3 (not 5.6.x, which reverted the SQS transport change).

Code changes the upgrade required:

  • plane/urls.py β€” gate the debug-toolbar URL include on apps.is_installed("debug_toolbar"). django-debug-toolbar 6.0 ships a real model (HistoryEntry) that raises during manage.py check when the app isn't in INSTALLED_APPS (test settings use DEBUG=True but don't install it).
  • plane/db/migrations/0122_… β€” a state-only AlterField for three ManyToManyFields (issue.assignees, draftissue.assignees, module.members) that use through_fields (Django 5.1 normalized M2M deconstruction). sqlmigrate confirms it is a no-op β€” zero database impact; required only so makemigrations --check stays green.
  • plane/tests/contract/app/test_authentication.py β€” add a module-level autouse cache.clear() fixture. This fixes 8 pre-existing test failures that are unrelated to the upgrade (verified identical on the Django 4.2 preview baseline): the per-IP AuthenticationThrottle stores history in the shared cache and the magic sign-in/up test classes didn't reset it between tests.

A full migration plan / audit write-up is included at apps/api/docs/django-5.2-migration-plan.md.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Feature (non-breaking change which adds functionality)
  • Improvement (change that would cause existing functionality to not work as expected)
  • Code refactoring
  • Performance improvements
  • Documentation update

Screenshots and Media (if applicable)

Test Scenarios

Verified in the containerized harness (docker-compose-test.yml: python:3.12.5-alpine, Postgres 15.7, Valkey, RabbitMQ, MinIO) on Django 5.2.15:

  • pip install -r requirements/test.txt β€” resolves, no conflicts.
  • manage.py check β€” "System check identified no issues".
  • manage.py makemigrations --check --dry-run β€” no changes.
  • manage.py migrate β€” full history (db 0001β†’0122 + django_celery_beat + license + sessions) applies cleanly on Postgres 15.
  • pytest (full suite) β€” 393 passed, 0 failed.
  • ENABLE_DRF_SPECTACULAR=1 manage.py spectacular β€” schema generates under drf-spectacular 0.29.

Recommended pre-merge smoke (not yet run): boot the api / worker / beat / migrator entrypoints against a local stack and exercise an auth flow, a file upload (S3/MinIO), and a Celery task + scheduled beat task.

References


πŸ€– Generated with Claude Code

Summary by CodeRabbit

  • Documentation

    • Added a detailed Django upgrade plan with validation steps, rollout guidance, risk notes, and rollback instructions.
  • Bug Fixes

    • Improved stability of authentication tests by clearing cached throttle state between test runs.
    • Made the debug toolbar route appear only when it is actually installed.
  • Chores

    • Updated core API, local development, and test dependencies to newer versions.
    • Included a database migration to keep user assignment relationships consistent.

Upgrade Django 4.2.30 LTS β†’ 5.2.15 LTS and bump all Django-coupled
dependencies to versions that officially support 5.2 (DRF 3.17.1,
channels 4.3.2, django-cors-headers 4.9.0, django-filter 25.2,
django-storages 1.14.6, django-redis 7.0.0, celery 5.5.3,
django-celery-beat 2.9.0, django-celery-results 2.6.0,
drf-spectacular 0.29.0, scout-apm 3.5.3, psycopg 3.3.4,
whitenoise 6.12.0, django-debug-toolbar 6.0.0, pytest-django 4.12.0).
OpenTelemetry set, django-crum and pytz held (already 5.2-compatible).

Code changes the upgrade required:
- urls.py: gate the debug-toolbar URL include on apps.is_installed(),
  since django-debug-toolbar 6.0 ships a model that errors when the app
  isn't in INSTALLED_APPS (test settings run DEBUG=True but don't install it).
- migration 0122: state-only AlterField for three M2M fields using
  through_fields (Django 5.1 deconstruction normalization); sqlmigrate is a
  no-op, zero DB impact.
- test_authentication.py: module-level autouse cache.clear() fixture to fix
  8 pre-existing throttle test-isolation failures (identical on the 4.2
  baseline) so the suite is green.

Verified on python:3.12-alpine + Postgres 15.7: check clean,
makemigrations --check clean, full migrate applies, pytest 393 passed.

Adds the migration plan/audit write-up under apps/api/docs/.
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

πŸ“ Walkthrough

Walkthrough

Adds a Django 4.2β†’5.2 migration plan doc, updates dependency pins, guards debug_toolbar URL wiring on app installation, resets auth throttle cache in contract tests, and adds a migration that normalizes M2M through_fields definitions.

Changes

Django 5.2 migration

Layer / File(s) Summary
Migration plan
apps/api/docs/django-5.2-migration-plan.md
Records the migration scope, verification status, execution checklist, acceptance criteria, rollback plan, risks, and out-of-scope follow-ups.
Compatibility updates
apps/api/requirements/base.txt, apps/api/requirements/local.txt, apps/api/requirements/test.txt, apps/api/plane/urls.py, apps/api/plane/tests/contract/app/test_authentication.py
Updates requirement pins, checks for debug_toolbar before route injection, and clears auth throttle cache around each contract test.
M2M migration
apps/api/plane/db/migrations/0122_alter_draftissue_assignees_alter_issue_assignees_and_more.py
Alters DraftIssue.assignees, Issue.assignees, and Module.members to use explicit through_fields on AUTH_USER_MODEL.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I thumped through pins with bunny grace,
Then tucked a debug toolbar in its place.
I scrubbed the cache and rewired the thread,
And hopped through Django 5.2 ahead.
✨

πŸš₯ Pre-merge checks | βœ… 5
βœ… Passed checks (5 passed)
Check name Status Explanation
Title check βœ… Passed The title clearly and concisely summarizes the main change: upgrading Django from 4.2 to 5.2.
Description check βœ… Passed The PR description covers the required template sections and includes the change summary, type, tests, screenshots note, and references.
Docstring Coverage βœ… Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check βœ… Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check βœ… Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
πŸ“ Generate docstrings
  • Create stacked PR
  • Commit on current branch
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/django-5.2-upgrade

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

πŸ€– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/plane/tests/contract/app/test_authentication.py`:
- Around line 23-36: The module-wide auth cache fixture is wiping the entire
shared Redis cache, which can affect unrelated state across tests. Update the
`_reset_auth_throttle_cache` fixture in `test_authentication.py` to remove only
`AuthenticationThrottle` entries, using targeted deletion of
`throttle_authentication_*` keys (for example via a helper like
`_clear_auth_throttle_keys`) instead of calling `cache.clear()`. Keep the
cleanup before and after the test via the fixture, but scope it to the throttle
cache keys only.
πŸͺ„ Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b0bac99d-03e4-42a5-a225-07cff70464fe

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 90ae845 and 8c5b7fb.

πŸ“’ Files selected for processing (7)
  • apps/api/docs/django-5.2-migration-plan.md
  • apps/api/plane/db/migrations/0122_alter_draftissue_assignees_alter_issue_assignees_and_more.py
  • apps/api/plane/tests/contract/app/test_authentication.py
  • apps/api/plane/urls.py
  • apps/api/requirements/base.txt
  • apps/api/requirements/local.txt
  • apps/api/requirements/test.txt

Comment on lines +23 to +36
@pytest.fixture(autouse=True)
def _reset_auth_throttle_cache():
"""Clear the shared cache around every test in this module.

The auth endpoints apply a per-IP throttle (AuthenticationThrottle) whose
request history lives in the Django cache. Because the test session reuses a
single cache, that count leaks across tests and trips RATE_LIMIT_EXCEEDED in
classes that don't reset it. This mirrors the per-class ``_clear_state``
fixtures already used by the throttle / verify-attempt classes, applied
module-wide so every auth test starts from a clean throttle state.
"""
cache.clear()
yield
cache.clear()

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.

🩺 Stability & Availability | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Cache backend used by tests =="
fd -t f 'test.*settings.*|settings.*test.*|settings.py|common.py' apps/api | xargs -r rg -n -C2 'CACHES|django_redis|RedisCache|LocMemCache'

echo
echo "== Whole-cache clears in tests =="
rg -n -C2 '\bcache\.clear\s*\(' apps/api/plane/tests

echo
echo "== Authentication throttle definitions / keying =="
rg -n -C3 'AuthenticationThrottle|RATE_LIMIT_EXCEEDED|throttle' apps/api/plane

Repository: makeplane/plane

Length of output: 32504


Avoid flushing the entire shared cache; scope cleanup to authentication throttle keys.

The cache.clear() calls on lines 34 and 36 purge the entire Redis cache alias. In a shared backend setup (confirmed in apps/api/plane/settings/common.py) used with pytest-xdist, this wipes unrelated cached state (sessions, feature flags, etc.) and introduces cross-test flakiness.

Replace cache.clear() with targeted deletion of keys matching the DRF throttle pattern throttle_authentication_*, or configure a dedicated cache alias for test isolation.

Example targeted cleanup approach
from django.core.cache import cache
from django_redis import get_redis_connection

# DRF key pattern: throttle_<scope>_<identity>
# For AuthenticationThrottle (scope="authentication"), keys match "throttle_authentication_*"
THROTTLE_PREFIX = "throttle_authentication_"

def _clear_auth_throttle_keys():
    """Delete only auth throttle keys to avoid wiping unrelated cache data."""
    redis_client = get_redis_connection("default")
    # Scan and delete matching keys
    keys = list(redis_client.keys(f"{THROTTLE_PREFIX}*"))
    if keys:
        redis_client.delete(*keys)

`@pytest.fixture`(autouse=True)
def _reset_auth_throttle_cache():
    _clear_auth_throttle_keys()
    yield
    _clear_auth_throttle_keys()
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/api/plane/tests/contract/app/test_authentication.py` around lines 23 -
36, The module-wide auth cache fixture is wiping the entire shared Redis cache,
which can affect unrelated state across tests. Update the
`_reset_auth_throttle_cache` fixture in `test_authentication.py` to remove only
`AuthenticationThrottle` entries, using targeted deletion of
`throttle_authentication_*` keys (for example via a helper like
`_clear_auth_throttle_keys`) instead of calling `cache.clear()`. Keep the
cleanup before and after the test via the fixture, but scope it to the throttle
cache keys only.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant