Symptom
On the detail page of a single object (/admin2/<app>/<model>/<pk>/change/), the action toolbar shows the changelist multi-select actions (the ones declared on ModelAdmin.actions = [...]) but does not show the per-object actions registered via django-object-actions (change_actions = [...]) — the single-pk operations that should appear on the detail page only.
Confirmed on django-admin-react==1.0.1 (latest stable), django-object-actions declared correctly on the ModelAdmin (verified via the legacy /admin/ HTML detail page, which renders them as expected).
Expected
On a detail page, two distinct sets of buttons should be visible:
- Per-object actions (
change_actions): operations meaningful on the single object being viewed (e.g. "Reprocess", "Approve", "Mark as reviewed"). These are declared on the ModelAdmin via django-object-actions.DjangoObjectActions.change_actions. They take no multi-select — they always operate on the current pk.
- Edit / Delete standard admin buttons.
The bulk changelist actions ("Delete selected …", "Disable All Selected …", "Reprocess selected …") should not appear on the detail page, or at minimum should be visually demoted — they're list-page semantics applied to a "selection" of one, which is confusing.
Actual
Detail page renders, in order:
- All
ModelAdmin.actions (bulk operations), worded "selected files" / "selected items".
Edit.
Delete.
No change_actions (single-pk buttons) appear, even when the ModelAdmin declares them and the REST API exposes them at /api/v1/admin/<app>/<model>/<pk>/change-actions/ (or equivalent).
PR #562 ("detail-page admin action buttons reusing the changelist actions API") shipped the wrong primitive: it surfaces the changelist action endpoint (multi-select, list semantics) on the detail page instead of the single-pk change-action endpoint (django-object-actions).
Probable cause
DetailPage.tsx is wired to the changelist actions endpoint (POST /api/.../actions/) with pks=[currentPk] rather than the change-actions endpoint that surfaces ModelAdmin.change_actions from django-object-actions.
The REST API side appears to already expose change_actions (see #540 / be589ad feat(api): object-level change-page actions (django-object-actions)), so the gap is on the SPA side: it's calling the wrong endpoint.
Suggested fix direction
In DetailPage.tsx, fetch and render change_actions from the per-object endpoint introduced in #540 instead of (or in addition to) the changelist actions. The bulk "selected files" actions should either be removed from the detail page entirely, or rendered only in a clearly separate group ("Apply to this object as a list of 1") for parity with the legacy admin — but per-object actions must take precedence and be present.
Repro
- Declare a ModelAdmin with both
actions = [bulk_op] and change_actions = ['per_object_op'] via django-object-actions.
- Open the SPA detail page for any instance:
/admin2/<app>/<model>/<pk>/change/.
- Observe:
bulk_op button is present; per_object_op button is absent.
- Open the same instance in the legacy admin:
/admin/<app>/<model>/<pk>/change/.
- Observe:
per_object_op IS present in legacy, confirming the ModelAdmin declares it and the API surfaces it.
References
Symptom
On the detail page of a single object (
/admin2/<app>/<model>/<pk>/change/), the action toolbar shows the changelist multi-select actions (the ones declared onModelAdmin.actions = [...]) but does not show the per-object actions registered viadjango-object-actions(change_actions = [...]) — the single-pk operations that should appear on the detail page only.Confirmed on
django-admin-react==1.0.1(latest stable),django-object-actionsdeclared correctly on the ModelAdmin (verified via the legacy/admin/HTML detail page, which renders them as expected).Expected
On a detail page, two distinct sets of buttons should be visible:
change_actions): operations meaningful on the single object being viewed (e.g. "Reprocess", "Approve", "Mark as reviewed"). These are declared on the ModelAdmin viadjango-object-actions.DjangoObjectActions.change_actions. They take no multi-select — they always operate on the currentpk.The bulk changelist actions ("Delete selected …", "Disable All Selected …", "Reprocess selected …") should not appear on the detail page, or at minimum should be visually demoted — they're list-page semantics applied to a "selection" of one, which is confusing.
Actual
Detail page renders, in order:
ModelAdmin.actions(bulk operations), worded "selected files" / "selected items".Edit.Delete.No
change_actions(single-pk buttons) appear, even when the ModelAdmin declares them and the REST API exposes them at/api/v1/admin/<app>/<model>/<pk>/change-actions/(or equivalent).PR #562 ("detail-page admin action buttons reusing the changelist actions API") shipped the wrong primitive: it surfaces the changelist action endpoint (multi-select, list semantics) on the detail page instead of the single-pk change-action endpoint (
django-object-actions).Probable cause
DetailPage.tsxis wired to the changelist actions endpoint (POST /api/.../actions/) withpks=[currentPk]rather than the change-actions endpoint that surfacesModelAdmin.change_actionsfromdjango-object-actions.The REST API side appears to already expose
change_actions(see #540 /be589ad feat(api): object-level change-page actions (django-object-actions)), so the gap is on the SPA side: it's calling the wrong endpoint.Suggested fix direction
In
DetailPage.tsx, fetch and renderchange_actionsfrom the per-object endpoint introduced in #540 instead of (or in addition to) the changelist actions. The bulk "selected files" actions should either be removed from the detail page entirely, or rendered only in a clearly separate group ("Apply to this object as a list of 1") for parity with the legacy admin — but per-object actions must take precedence and be present.Repro
actions = [bulk_op]andchange_actions = ['per_object_op']viadjango-object-actions./admin2/<app>/<model>/<pk>/change/.bulk_opbutton is present;per_object_opbutton is absent./admin/<app>/<model>/<pk>/change/.per_object_opIS present in legacy, confirming the ModelAdmin declares it and the API surfaces it.References
be589adfrontend/apps/web/src/pages/DetailPage.tsx