Internals¶
Notes on the implementation, aimed at contributors and at developers debugging an integration. Nothing here is part of the public Python API, though the templates named below are meant to be overridden by projects.
How moderation modifies Versioning’s UI¶
monkeypatch.pyModeration monkeypatches parts of djangocms-versioning’s admin:
get_state_actionsgains a Submit for moderation icon button next to draft versions in the version table (see Admin action icons), and additional checks are added to versioning’s check framework to block operations (edit, revert, discard, …) at certain stages of moderation.cms_toolbars.pyReplaces versioning’s toolbar with
ModerationToolbar, which swaps the Publish button for Submit for moderation / In collection “…” buttons and disables Edit for review-locked content.admin.pyBesides the model admins, this module generates the bulk-action confirmation views (
approve,rework,publish,resubmit,delete_selected). The available bulk actions are filtered per user by moderation’s internal role logic (see Roles and permissions), so different users see different action menus on the same changelist.
Admin action icons¶
Per-row actions in moderation’s changelists follow django CMS’s convention
and are rendered as icon buttons — an <a class="btn cms-action-btn">
around a 20×20 glyph — rather than as text links. The wording of the action
is kept as the button’s title, which is both its tooltip and its
accessible name.
Each button is a small, overridable template. All paths below are relative
to djangocms_moderation/templates/djangocms_moderation/:
Tooltip |
Template |
Shown in |
|---|---|---|
Submit for moderation |
|
versioning’s version table, on moderated drafts |
Submit for unpublishing |
|
versioning’s version table, on moderated
published versions — only while
|
Edit Collection Settings |
|
collections changelist |
View Requests |
|
collections changelist |
View Comments |
|
collections and requests changelists |
Where django CMS’s own icon font offers a suitable glyph, the template uses
it directly (<span class="cms-icon cms-icon-pencil">). The two submit
actions have no counterpart in that font, so they embed Bootstrap Icons instead: send-check for submitting
content to be published, send-dash for submitting it to be unpublished.
Bootstrap Icons is MIT licensed; the notice is reproduced in LICENSE.txt.
Those two icons are inlined in the template rather than shipped as static
.svg files and referenced with <img>. As inline markup the SVG
inherits fill="currentColor" from the button, so it follows django CMS’s
light and dark admin themes; an image reference would resolve the colour in
the SVG’s own context and stay black on a dark background.
Both extend djangocms_moderation/icons/base.html, which renders the
anchor and leaves three blocks to fill in — name (appended to the CSS
class as cms-moderation-action-{name}), title (the tooltip) and
icon (the glyph). To swap in a different glyph, shadow the template in
your project and override just the icon block:
{# myproject/templates/djangocms_moderation/icons/submit_for_moderation.html #}
{% extends "djangocms_moderation/icons/base.html" %}
{% load i18n %}
{% block title %}{% translate "Send to review" %}{% endblock %}
{% block name %}submit-for-moderation{% endblock %}
{% block icon %}<span class="cms-icon cms-icon-moderate"></span>{% endblock %}
The buttons are sized and coloured by django CMS’s cms.admin.css, which
the version table already loads through versioning’s admin; moderation’s own
changelists add djangocms_moderation/css/actions.css on top.
The tree changelist¶
When a page is added to a collection, moderated draft content used by
plugins on that page (for example aliased content) is added along with it.
Presenting those additions as a flat list would hide why they are in the
collection, so the requests changelist is rendered as a tree (materialised
path trees, via the ModerationRequestTreeNode model): nested entries
belong to the page they were collected with.
The changelist is read-only as a tree: ModerationRequestTreeAdmin is a
plain ModelAdmin ordered by path, which lists the nodes depth first,
and each row is indented by its depth in the ID column. Requests are
nested when they are collected, never by rearranging them here, so no client
side tree code is involved.
Which materialised path implementation backs the model follows the page
tree’s CMS_TREE_BACKEND setting: django-treebeard by default, or the
dependency free implementation django CMS 5.0.10 and 5.1.1 added in
cms.utils.mptree when it is set to "mptree". Both write the same
columns, so switching is a restart rather than a migration. The core
implementation reads the tree from a parent foreign key where treebeard
reads it from path; ModerationRequestTreeNode maintains parent
under either backend, and fix_tree() re-derives it from the paths if rows
were ever written behind the tree API’s back.
A consequence of modelling the relationship rather than the request is that the same content object may appear several times in the tree — once per page that pulled it in, plus once if it was added individually. It is still only one moderation request: acting on any occurrence acts on all of them, and removing it from the collection removes every occurrence.
Confirmation pages (legacy)¶
The models ConfirmationPage and
ConfirmationFormSubmission (admin sections Confirmation Pages and
Confirmation Form Submissions) belong to a django CMS Moderation 1.x
feature where a reviewer could be required to fill in a form before
approving a step. The view rendering these pages still exists, but the
current bulk-action approval flow does not enforce or link to them — the
feature is effectively dormant and kept for data compatibility.