Skip to main content

DjSuperAdmin

PyPI version Codecov CI status License

✍️ Edit contents directly on your page with Django

Here's how it works

djsuperadmin demo

Superusers get an inline editor (SunEditor, lazy-loaded from a CDN on first edit) right on the rendered page. Everyone else just sees the plain content.

Compatibility

  • Django 2.0 → latest (tested 2.2 → 6.0)
  • Python 3.6+
  • Zero runtime dependencies (other than Django itself)

Installation

pip install djsuperadmin
# or
uv add djsuperadmin

Setup

Add the app to INSTALLED_APPS:

INSTALLED_APPS = [
    # ...
    "djsuperadmin",
]

Include the urls only if you use the built-in Content model (i.e. the bare-string tag form shown below):

from django.urls import path, include

urlpatterns = [
    # ...
    path("", include("djsuperadmin.urls")),
]

Finally, load the template tags and drop {% djsuperadminjs %} once in your footer. It injects the djsuperadmin bundle (which lazy-loads SunEditor on first edit), and renders only for authenticated superusers (empty string for everyone else):

{% load djsuperadmintag %}

<!-- ... your page ... -->

{% djsuperadminjs %}

Usage

Simple (bare string)

Pass a default string. djsuperadmin stores it in its built-in Content model, keyed by a hash of the text and auto-created on first render. Requires the urls to be included.

{% load djsuperadmintag %}

{% superadmin_content 'Some default text' %}

Raw content

Same as above but with a plain textarea editor (no WYSIWYG) — good for plain text or snippets. Note the tag name is superadmin_raw_content:

{% superadmin_raw_content 'Some default text' %}

Bind to a model attribute

Both tags also accept an object and an attribute name. Superusers see an editable element (a <div class="djsuperadmin"> for WYSIWYG, a <span> for raw), everyone else sees the plain value:

{% superadmin_content my_object 'body' %}
{% superadmin_raw_content my_object 'body' %}

Advanced: your own content model + endpoint

Mix in DjSuperAdminMixin and expose a GET/PATCH endpoint. The mixin raises NotImplementedError if the two url properties are not defined.

from django.db import models
from djsuperadmin.mixins import DjSuperAdminMixin


class MyContent(models.Model, DjSuperAdminMixin):
    body = models.TextField()

    @property
    def superadmin_get_url(self):
        return f"/api/mycontent/{self.pk}"

    @property
    def superadmin_patch_url(self):
        return f"/api/mycontent/{self.pk}"

Your endpoint must:

  • GET → return JSON {"content": <value>}
  • PATCH with body {"content": <value>} → save it

Then render it like any other object:

{% superadmin_content my_content 'body' %}

Settings

DJSUPERADMIN = {"INPLACE_EDIT": True}

When INPLACE_EDIT is True, contents are edited right on the page instead of in a modal: raw contents via contenteditable, and WYSIWYG contents via an inline SunEditor (its toolbar docks above the content while editing; click the toolbar's save button to commit, or press Esc to cancel). Defaults to False (modal editing).

Version history / revert

Every save keeps the previous value. Hovering an editable content shows a toolbar (✏️ edit + ⟲ history); the history icon lists past versions (timestamp + preview) and clicking one restores it — reverting is itself an undoable save. Works out of the box for the built-in Content model (capped by MAX_VERSIONS, default 20). Your own models opt in by exposing a superadmin_history_url — see the docs.

DJSUPERADMIN = {"INPLACE_EDIT": True, "MAX_VERSIONS": 20}

Point IMAGE_GALLERY_URL at an endpoint that returns {"result": [{"src": "...", "name": "..."}, ...]} and the WYSIWYG toolbar gains an "insert image from gallery" button. This is designed to plug into a CMS media library. IMAGE_UPLOAD_URL (optional) enables direct uploads.

DJSUPERADMIN = {
    "INPLACE_EDIT": True,
    "IMAGE_GALLERY_URL": "/api/media/",  # returns the media list as JSON
}

The WYSIWYG editor (SunEditor) is lazy-loaded from jsDelivr. To self-host it — e.g. under a strict Content-Security-Policy — override the URLs:

DJSUPERADMIN = {
    "SUNEDITOR_JS": "/static/vendor/suneditor.min.js",
    "SUNEDITOR_CSS": "/static/vendor/suneditor.min.css",
}

Development

Contributions welcome — see CONTRIBUTING.md. Tooling is uv (Python) + pnpm (JS build & docs), with the frontend bundle built by Vite.

make install      # uv sync --dev && pnpm install
make test         # flake8 + pytest with coverage
make format       # black .
make lint         # flake8 djsuperadmin
make build        # rebuild djsuperadmin/static/djsuperadmin/djsuperadmin.bundle.js
make migrations   # uv run python manage.py makemigrations
make docs-dev     # VitePress docs (also: docs-build, docs-preview)

Run the demo / test project (example/, settings module example.djsuperadmin_example.settings):

uv run python manage.py migrate
uv run python manage.py createsuperuser
uv run python manage.py runserver   # log in at /admin/, then open /

Documentation

Full docs: https://bnznamco.github.io/djsuperadmin/

Metadata

Release files for djsuperadmin 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for djsuperadmin 1.0.1
File Size Uploaded Provenance
djsuperadmin-1.0.1.tar.gz 18.5 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for djsuperadmin 1.0.1
File Interpreter ABI Platform
djsuperadmin-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 34.9 kB

Release files / djsuperadmin-1.0.1.tar.gz

Download URL djsuperadmin-1.0.1.tar.gz
Size 18.5 kB
Tags Source
SHA-256 checksum
How to use checksums
289c24a11bf1148e6e12f75d076ec4133741813e68c742c12907d5a3b54eed72
BLAKE2b-256 checksum
How to use checksums
293060868833f07bb5476200012be6287c3eb36ff98fa7abdfd6e71c2ff0d039
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / djsuperadmin-1.0.1-py3-none-any.whl

Download URL djsuperadmin-1.0.1-py3-none-any.whl
Size 16.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ac16a5947fc5f5150c04b2261057fee3a0ce0da0b16181d3e571c6ca06da986a
BLAKE2b-256 checksum
How to use checksums
ac116949827a5b1b80fec3dbb42a88a15d523a63ee51407d064923fa92f310df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Security for djsuperadmin 1.0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page