Skip to content

Support for Django 5.2 / 6.0 - #194

Open
stereodamage wants to merge 3 commits into
jazzband:masterfrom
stereodamage:feat/django-52-60-support
Open

stereodamage wants to merge 3 commits into
jazzband:masterfrom
stereodamage:feat/django-52-60-support

Conversation

@stereodamage

@stereodamage stereodamage commented Jul 3, 2026 •

Copy link
Copy Markdown

Description

Add Django 5.2/6.0 support, drop EOL Django and Python versions

Closes #169, #188

Motivation and Context

The package currently supports Django 3.2 and 4.2, both of which have reached
end of extended support (April 2024 and April 2026 respectively, per the
supported versions table).
Meanwhile Django 5.1+ introduced changes that this package must adapt to —
one of which causes silent data loss in async views.

How Has This Been Tested?

Python 3.10–3.13 × Django 5.2 / 6.0 / main, with 3.10/3.11 excluded for
6.0+ (Django 6.0 requires Python 3.12+).
Full suite verified locally on Django 5.2 (Python 3.11) and Django 6.0
(Python 3.13), including a -W error::DeprecationWarning run — no
deprecation warnings on either.

Types of changes

  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Changes

Async session API support (bug fix)

Django 5.1 added an async API to all session backends
(aget(), asave(), aload(), …), and Django 5.0 added
auth.alogin() and friends.
Django's async DBStore methods do not delegate to their sync equivalents, so
this package's sync-only overrides were bypassed entirely in async code paths:
sessions saved via alogin() or any async view were written with user,
user_agent and ip all NULL — silently, since the model fields are
nullable. This defeats the package's core purpose.

Fixed by mirroring the four sync overrides with async counterparts in
user_sessions.backends.db.SessionStore:

  • aset() — captures user_id; note alogin() writes the session key via
    aset(), bypassing __setitem__
  • _aget_session_from_db() — restores user_id, flags modified on
    user-agent/IP change
  • acreate() — resets the session cache
  • acreate_model_instance() — persists user_agent, user_id and ip

Covered by new tests exercising the same call sequence alogin() uses.

GeoIP2 test fixtures

Django 5.1 changed GeoIP2 to open a single database,
preferring the city database when available, so country lookups now hit the
city db. The city test fixture gained a country-only record for 8.8.8.8;
the fixture generation stays compatible with the pre-5.1 lookup path.

Dropped versions (breaking)

Dead code removed accordingly: the pkg_resources version fallback, the
django.contrib.gis.geoip test fallback (API removed in Django 3.0), and a
Django version guard in tests.

Tooling fixes

  • The release workflow still invoked setup.py, which no longer exists since
    the move to pyproject.toml; it now builds with python -m build
    (verified: artifacts build and pass twine check)
  • migratesessions used the Python 2-only e.message attribute, raising
    AttributeError on any Python 3
  • The Makefile referenced django-admin.py,
    removed in Django 4.0
  • The example app lacked the request context processor required by the
    admin sidebar

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Support the async session API introduced in Django 5.1 by mirroring the
sync `SessionStore` overrides with async counterparts (`aset`, `acreate`,
`_aget_session_from_db`, `acreate_model_instance`). Without these, sessions
saved from async code (e.g. via `auth.alogin()`) silently lost the user,
user_agent and ip values, since Django's async DBStore methods do not
delegate to their sync equivalents. Note that `alogin()` writes the
session key through `aset()`, bypassing `__setitem__`.

Adapt the GeoIP test fixtures to Django 5.1+, where GeoIP2 uses a
single database: country lookups now hit the city database when
GEOIP_CITY is configured, so the city fixture needs a country-only
record for 8.8.8.8. Remains compatible with the country-database
lookup path of older Django.

Drop support for Django 3.2 and 4.2 (EOL April 2024 and April 2026)
and Python 3.7-3.9, raising the floor to Django 5.2 LTS and Python
3.10. Remove code the new floor makes dead: the pkg_resources version
fallback, the `django.contrib.gis.geoip` test fallback (API removed in
Django 3.0), and the async-API version guard in tests.

Also fix issues surfaced while validating:
- release workflow invoked setup.py, which no longer exists; build
  with python -m build instead
- `migratesessions` used the Python 2-only e.message attribute
- Makefile referenced django-admin.py, removed in Django 4.0
- example app was missing the request context processor required by
  the admin sidebar

Test matrix is now Python 3.10-3.13 x Django 5.2/6.0/main.
@codecov

codecov Bot commented Jul 3, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.63014% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 98.48%. Comparing base (e2bf17e) to head (92f7721).
⚠️ Report is 5 commits behind head on master.

Files with missing lines Patch % Lines
...er_sessions/management/commands/migratesessions.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #194      +/-   ##
==========================================
+ Coverage   97.22%   98.48%   +1.25%     
==========================================
  Files          24       25       +1     
  Lines         721      790      +69     
  Branches       56       31      -25     
==========================================
+ Hits          701      778      +77     
+ Misses         14        8       -6     
+ Partials        6        4       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@stereodamage stereodamage reopened this Jul 4, 2026
Adds tests for the uncovered paths:
- `aset()` with a non-auth key
- anonymous session and idempotent re-run
@stereodamage
stereodamage marked this pull request as ready for review July 4, 2026 10:30

This branch has not been deployed

No deployments
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.

Drop unsupported versions of Django

1 participant