Skip to content

Commit 7cb3d63

Browse files
MartinCastroAlvarezmartin-castro-laminr-aiclaude
authored
feat: Django 4.2 LTS support + release 1.5.0 (#622) (#645)
Closes #622 — the cross-repo Django 4.2 chain is now complete. ## What Relax this package's Django pin from `>=5.0,<7.0` to `>=4.2,<7.0`, bump the API + MCP dep constraints to their 4.2-aware floors, add a 4.2 dimension to CI, and update the README's Requirements section + classifier list to advertise 4.2. | Repo | Before | After | Released | |---|---|---|---| | `django-admin-rest-api` | `django >=5.0` | `django >=4.2` | 1.1.0 (PyPI) | | `django-admin-mcp-api` | `django >=5.0` | `django >=4.2` | 1.1.0 (PyPI) | | `django-admin-react` | `django >=5.0` | `django >=4.2` | **1.5.0 (this PR)** | Why the constraint tightens on `django-admin-mcp-api` even though its public range stays the same: the 1.0.x line pins ``django>=5.0``, so a consumer on Django 4.2 would resolve to an mcp version that refuses to install. Bumping the floor to ``>=1.1.0`` keeps the install promise honest. ## CI matrix Added a `matrix.django: ["4.2", "5.2"]` dimension; runtime install swaps Django via the venv's `pip install "django~=<matrix>.0"`. Today both matrix cells run py3.12. ## README freshness While here, two doc updates aligned to the post-#631 reality: - `PRIMARY_COLOR` default is now `None` (the resolver reads `AdminSite.site_primary_color` next, falling back to the built-in `#2563eb`). The settings-block example reflects the None default. - New "Accent colour" subsection in Branding documents the full resolution order + the `site_primary_color` AdminSite-attr convention, with a worked `AcmeAdminSite` example. The "Requirements" line now reads `Django: 4.2 LTS, 5.0, 5.1, 5.2 LTS, 6.0 (and any later 6.x)` — accurate for what the wheel will actually install on. ## Verification - `poetry run pytest -q` — **61 / 61 ✓** on Django 4.2.30 - `poetry run pytest -q` — **61 / 61 ✓** on Django 5.2.14 (no regression) - `pnpm test` — **187 / 187 ✓** - `pnpm -r typecheck` ✓ - `pnpm lint` ✓ - Cross-repo install resolved end-to-end: rest-api 1.1.0 + mcp-api 1.1.0 + django 4.2.30 + this package 1.5.0 in one venv. ## Minor bump rationale `1.4.13` → `1.5.0`. New supported environment (Django 4.2 LTS) per SemVer's "additive features that broaden compatibility" guideline. Matches the symmetric 1.1.0 minor bumps on `django-admin-rest-api` and `django-admin-mcp-api`. Closes #622. Co-authored-by: Martin Castro Laminrs <mcastro@laminr.ai> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 91e8ed1 commit 7cb3d63

4 files changed

Lines changed: 76 additions & 26 deletions

File tree

.github/workflows/ci.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,16 +50,28 @@ concurrency:
5050

5151
jobs:
5252
backend:
53-
name: Backend (pytest)
53+
name: Backend (pytest py${{ matrix.python }} / Django ${{ matrix.django }})
5454
runs-on: ubuntu-latest
55+
strategy:
56+
fail-fast: false
57+
matrix:
58+
# Django 4.2 LTS is supported through April 2026 (#622). Add it
59+
# alongside 5.x and 6.0 so the package keeps working for the
60+
# majority of installed Django by deployment count.
61+
python: ["3.12"]
62+
django: ["4.2", "5.2"]
63+
# 4.2 added Python 3.13 support in 4.2.16 but pip may resolve to
64+
# an earlier 4.2.x; skip 3.13 + 4.2 conservatively. (We only
65+
# exercise py3.12 here today; the matrix is set up for an easy
66+
# future expansion.)
5567
steps:
5668
- name: Checkout
5769
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
5870

5971
- name: Set up Python
6072
uses: actions/setup-python@0b93645e9fea7318ecaed2b359559ac225c90a2b # v5.3.0
6173
with:
62-
python-version: "3.12"
74+
python-version: ${{ matrix.python }}
6375

6476
- name: Install Poetry
6577
# Poetry is pinned to the version that generated poetry.lock (see
@@ -72,6 +84,9 @@ jobs:
7284
- name: Install dependencies (locked)
7385
run: poetry install --no-interaction
7486

87+
- name: Pin Django to the matrix version
88+
run: poetry run pip install "django~=${{ matrix.django }}.0"
89+
7590
# pytest with coverage (per pyproject `addopts`), including
7691
# tests/test_security.py. `filterwarnings = ["error"]` means a new
7792
# warning fails the run.

README.md

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,12 @@ DJANGO_ADMIN_REACT = {
155155
"BRAND_LOGO_URL": None, # str | None — favicon + sidebar logo;
156156
# falls back to AdminSite.site_logo. Absolute
157157
# URL or a path under your STATIC_URL.
158-
"PRIMARY_COLOR": "#2563eb", # accent for primary buttons, links, and
159-
# active states. Hex only (validated);
160-
# injected as the --dar-primary CSS var, so
158+
"PRIMARY_COLOR": None, # accent for primary buttons, links, and
159+
# active states (#437 / #631). Hex only
160+
# (validated). None → reads
161+
# `site_primary_color` off your AdminSite;
162+
# fallback default is "#2563eb". Injected
163+
# as the --dar-primary CSS var, so
161164
# rebranding needs no React rebuild.
162165

163166
# Auth + API mount
@@ -212,10 +215,39 @@ Both values are written into the SPA index template as standard
212215
reads them at boot, so the first paint already carries the consumer's
213216
brand. No flash of the package's defaults.
214217

218+
#### Accent colour (`PRIMARY_COLOR` + `AdminSite.site_primary_color`)
219+
220+
`PRIMARY_COLOR` defaults to `None` so a custom `AdminSite` subclass can
221+
own the brand colour the same way it owns `site_header` / `site_logo`
222+
(#631). Resolution order — explicit setting wins, AdminSite is the
223+
structural default, built-in fallback last:
224+
225+
1. `DJANGO_ADMIN_REACT["PRIMARY_COLOR"]` — explicit per-deployment override.
226+
2. `<your AdminSite>.site_primary_color` — convention attribute on your
227+
custom `AdminSite` subclass (Django has no such attribute by default;
228+
add it as a constant alongside `site_header` / `site_logo`).
229+
3. `"#2563eb"` — the package's last-resort fallback.
230+
231+
Every layer runs through a strict hex-colour regex (`#rgb` / `#rgba` /
232+
`#rrggbb` / `#rrggbbaa`) before being injected into the SPA's `<style>`
233+
block, so a non-hex value at any layer falls through to the next — CSS
234+
injection is impossible at any source.
235+
236+
```python
237+
# myproject/admin.py
238+
from django.contrib.admin import AdminSite
239+
240+
class AcmeAdminSite(AdminSite):
241+
site_header = "Acme"
242+
site_title = "Acme Admin"
243+
site_logo = "/static/acme/logo.svg"
244+
site_primary_color = "#10b981" # emerald — used by legacy admin AND the SPA
245+
```
246+
215247
### Requirements
216248

217249
- **Python**: 3.10+
218-
- **Django**: 5.0, 5.1, 5.2, 6.0 (and any later 6.x)
250+
- **Django**: 4.2 LTS, 5.0, 5.1, 5.2 LTS, 6.0 (and any later 6.x)
219251
- **Database**: anything Django supports — the package is ORM-only,
220252
no direct SQL.
221253
- **Auth**: Django's built-in session + CSRF. Works with custom

poetry.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "django-admin-react"
3-
version = "1.4.13"
3+
version = "1.5.0"
44
description = "A drop-in React single-page admin for Django, driven entirely by ModelAdmin."
55
authors = ["django-admin-react contributors"]
66
license = "MIT"
@@ -13,6 +13,7 @@ classifiers = [
1313
"Development Status :: 5 - Production/Stable",
1414
"Environment :: Web Environment",
1515
"Framework :: Django",
16+
"Framework :: Django :: 4.2",
1617
"Framework :: Django :: 5.0",
1718
"Framework :: Django :: 5.1",
1819
"Framework :: Django :: 5.2",
@@ -39,26 +40,28 @@ include = [
3940

4041
[tool.poetry.dependencies]
4142
python = "^3.10"
42-
# Django 5.0 → 5.2 LTS → 6.x. Bump the upper bound when 7.0 ships and
43-
# we've verified the package still passes its test matrix on it.
44-
django = ">=5.0,<7.0"
43+
# Django 4.2 LTS → 5.2 LTS → 6.x (#622). Bump the upper bound when 7.0
44+
# ships and we've verified the package still passes its test matrix on
45+
# it. The dependent ``django-admin-rest-api`` package also supports 4.2
46+
# (since its 1.1.0).
47+
django = ">=4.2,<7.0"
4548
# The JSON REST API surface (every list / detail / create / update /
4649
# delete / action / history / autocomplete endpoint) lives in this
4750
# sibling package — same `ModelAdmin` source of truth, same permissions,
4851
# no new features. **This repo implements no API of its own**; it is the
4952
# React SPA super-layer over `django-admin-rest-api`. The package's URLs
5053
# are included by `django_admin_react.urls`, and consumers add
5154
# `"django_admin_rest_api"` to `INSTALLED_APPS` alongside this package.
52-
django-admin-rest-api = "^1.0.6"
55+
django-admin-rest-api = "^1.1.0"
5356
# `django-admin-mcp-api` — MCP-protocol adapter over the same REST API
5457
# so agents reach the SAME `ModelAdmin`-driven surface. Wire-protocol-only
5558
# layer; adds NO new functionality, permissions, or validation.
5659
# Constraint widened in v1.4.4 (#605) from the original `^0.1.0a0`
57-
# (which caps at `<0.2.0`) to `>=1.0.0,<2.0.0` so consumers can pin
58-
# the stable `1.x` mcp line. The wire contract is unchanged across
59-
# the 0.1.0a0 → 1.x bump; the version bump is a stability signal,
60-
# not an API break.
61-
django-admin-mcp-api = ">=1.0.0,<2.0.0"
60+
# to `>=1.0.0,<2.0.0`; raised again in v1.5.0 (#622) to `>=1.1.0,<2.0.0`
61+
# so a consumer on Django 4.2 actually gets a Django-4.2-compatible MCP
62+
# (the 1.0.x line pins ``django>=5.0``, which would refuse to install
63+
# alongside Django 4.2).
64+
django-admin-mcp-api = ">=1.1.0,<2.0.0"
6265

6366
[tool.poetry.group.dev.dependencies]
6467
# Dependabot #5: pytest's tmpdir handled symlinks unsafely

0 commit comments

Comments
 (0)