Skip to main content

Lucus enhances Django Admin with custom templates, static theming, and a multi-column dashboard.

Project description

django-lucus

Русский

django-lucus is a custom theme for Django’s built-in admin (django.contrib.admin): refreshed layout, bundled color schemes, and a multi-column dashboard on /admin/ by default (not the stock flat app list). You shape columns and links with LUCUS_DASHBOARD; leave it unset and Lucus builds columns from your registered apps. Install the lucus app. Admin URLs stay the same as in your project (often /admin/, from urls.py).

  • Appearance: Lucus replaces the admin “chrome” templates and loads CSS in order: lucus/css/style.csslucus-admin.css → the selected palette file lucus/css/schemes/<slug>.css.
  • Navigation: Django’s default admin app sidebar is turned off (AdminSite.enable_nav_sidebar = False).
  • Per signed-in user: chosen palette and light / dark / system appearance are stored in LucusAdminUiPreference.
  • Nav inside the admin: with LUCUS_SIDE_DASHBOARD_NAV (on by default), pages other than the index get a side or off-canvas menu in the same spirit as the home dashboard.
  • Lists and edit forms: bulk-action bars default to both above and below the changelist; save / delete controls on object forms can sit in a fixed bar at the bottom of the viewport. Project-wide toggles are LUCUS_ACTIONS_ON_TOP and LUCUS_ACTIONS_ON_BOTTOM in the settings table below; each ModelAdmin subclass can still override behavior the usual Django way.

Admin index — Dune palette, light appearance, full-page background

Index: multi-column LUCUS_DASHBOARD cards; header — palette, appearance, optional site / language selectors, user menu.

Changelist — Slate palette (example model)

Changelist: breadcrumbs, toolbar (pagination + search), bulk actions, results table, filter aside.

Change form — Dracula palette, dark appearance

Change form: fieldsets; fixed bottom action bar (save / delete). Palette and appearance are per-user (LucusAdminUiPreference).

Requirements

  • Python ≥ 3.10
  • Django: >=5.2,<7 (pyproject.toml)

Install

pip install django-lucus

Setup

Add lucus to INSTALLED_APPS and place it above django.contrib.admin:

INSTALLED_APPS = [
    # ...
    "lucus",
    "django.contrib.admin",
]

If another installed app defines the same template path as Lucus, lucus must come before it in the list; otherwise Django will load the wrong template. A common case is Rosetta: Lucus ships lucus/templates/rosetta/…. If rosetta appears earlier, those pages won’t use Lucus’s wrappers.

Then:

python manage.py migrate lucus

In production, run collectstatic so lucus/static/ is served.

Settings

Setting Type Default Effect
SITE_NAME str "Site" LUCUS_ADMIN_SITE_HEADER_TEMPLATE / site_title
LUCUS_ADMIN_SITE_HEADER_TEMPLATE str "Administration — {site}" admin.site.site_header = .format(site=SITE_NAME); only {site} or escape other {}
LUCUS_ADMIN_SITE_TITLE_USE_SITE_NAME bool True admin.site.site_title = SITE_NAME if true
LUCUS_ADMIN_BACKGROUND_IMAGE str / Path "" Full-page background: http(s)://, //, site path /…, or static path (no ..)
LUCUS_ADMIN_BACKGROUND_SCRIM_OPACITY float 0.88 Overlay on image, 0.01.0
LUCUS_ADMIN_LANGUAGE_SELECTOR bool (auto) False → hide header language <select>. Shown only if USE_I18N, len(LANGUAGES) > 1, LocaleMiddleware, set_language URL exists
LUCUS_ADMIN_SITE_SELECTOR bool (auto) False → hide django.contrib.sites header switcher. Shown if sites app + ≥2 Site rows
LUCUS_ADMIN_SITES AdminSite / list / tuple None AdminSite instances Lucus patches (each_context, get_urls, headers, …). Default: django.contrib.admin.site only. Example: LUCUS_ADMIN_SITES = (admin.site, my_site). base.html forms use {% url 'admin:lucus_save_ui' %}; other namespaces may need template overrides.
LUCUS_STAFF_THEME_PATH_PREFIXES tuple / list / str see below Staff: merge AdminSite.each_context on these URL prefixes (admin-like templates without admin_view). Default: /logs/, /rosetta/, /explorer/. () disables.
LUCUS_UI dict {} See below
LUCUS_EXTRA_STATIC_CSS str / list / tuple () Extra CSS after palette; no .., no leading /
LUCUS_EMPTY_VALUE_DISPLAY_WRAP bool True Wrap empty changelist cells in lucus-admin-empty
LUCUS_EMPTY_VALUE_PLACEHOLDER str "—" empty_value_display text
LUCUS_ACTIONS_ON_BOTTOM bool True Default ModelAdmin.actions_on_bottom at class level; override per subclass
LUCUS_ACTIONS_ON_TOP bool True Default ModelAdmin.actions_on_top at class level
LUCUS_DASHBOARD list / None None Dashboard; None → built-in grouped layout
LUCUS_DASHBOARD_APPEND_UNCOVERED bool True Grouped mode: append uncovered apps to last column
LUCUS_SIDE_DASHBOARD_NAV bool True Non-index admin: collapsible left nav from LUCUS_DASHBOARD column order. Off on index, popups, no permission

Palette / appearance: not in settings; stored per user. Slugs → lucus/static/lucus/css/schemes/<slug>.css. Context: lucus.theme.lucus_admin_extra_context via admin.site.each_context.

LUCUS_UI

Key Default Effect
help_as_icon True Field help_text behind ? / <details>
high_contrast_toggle False User menu: high contrast (localStorage, data-lucus-contrast on <html>)
clean_input_types False Map common HTML5 input types to text in admin (cf. Grappelli GRAPPELLI_CLEAN_INPUT_TYPES)
LUCUS_UI = {
    "help_as_icon": True,
    "high_contrast_toggle": False,
    "clean_input_types": False,
}

Sortable tabular inlines & placeholder inlines

  1. Drag-sort rowslucus.inlines.LucusSortableTabularInline or LucusSortableTabularInlineMixin + admin.TabularInline. sortable_field_name, optional sortable_excludes. Docstring: lucus/inlines.py.
  2. Inline between fieldsetsfieldsets entry with fields: (), classes containing "placeholder" and inline wrapper id (<formset.prefix>-group, e.g. items_set-group).

Third-party CSS (lucus/static/lucus/css/third_party/)

No extra Python deps. Non-admin/base.html staff views: LUCUS_STAFF_THEME_PATH_PREFIXES + lucus.context_processors.staff_integrations_theme.

Package File Included from
django-constance lucus/css/third_party/constance.css admin/base.html
django-filer lucus/css/third_party/filer.css admin/base.html
django-parler lucus/css/third_party/parler.css admin/base.html
django-rosetta lucus/css/third_party/rosetta.css rosetta/base.html
django-log-viewer (compatible) lucus/css/third_party/log_viewer.css log_viewer/logfile_viewer.html

LUCUS_DASHBOARD

Context: lucus_dashboard_columns from get_dashboard_for_request. Section link: {"label", "url"} or {"label", "admin_urlname"}. Section omitted if no link resolves.

Layout: [{ "column"?: 1–4, "classes"?: str, "sections": [{ "title", "links": [...] }] }, …]. Same column merges sections; classes from first dict.

Groups: [{ "column", "title", "links"?: [...], "app_labels"?: set|list|tuple|frozenset }, …]. links then models from app_labels; duplicate URLs dropped. list/tuple app_labels preserves order; set uses get_app_list order.

LUCUS_DASHBOARD_APPEND_UNCOVERED: True → unreferenced apps to last column; False → configured only.

LUCUS_DASHBOARD = [
    {
        "column": 1,
        "classes": "lucus-dashboard__col lucus-grid__col lucus-grid__col--3 lucus-grid__col--md-6 lucus-grid__col--sm-12 lucus-grid__col--xs-12",
        "sections": [
            {
                "title": "Education",
                "links": [
                    {"label": "Instructors", "admin_urlname": "admin:academy_instructor_changelist"},
                    {"label": "Courses", "url": "/admin/academy/course/"},
                ],
            },
        ],
    },
]
LUCUS_DASHBOARD = [
    {"column": 1, "title": "Authorization", "app_labels": {"auth"}},
]
LUCUS_DASHBOARD = [
    {
        "column": 2,
        "title": "Auth",
        "links": [{"label": "Users", "admin_urlname": "admin:auth_user_changelist"}],
        "app_labels": ("auth",),
    },
]

Stylesheet order

lucus/css/style.csslucus/css/lucus-admin.csslucus/css/schemes/<slug>.cssLUCUS_EXTRA_STATIC_CSS. Admin widget/inline/action JS: django.contrib.admin.

Custom palette: static lucus/css/<slug>.css + extend lucus.theme.BUNDLED_COLOR_SCHEMES.

admin/change_list_results.html overridden: .text before .sortoptions inside .lucus-th-heading-inner (replaces stock float sort icon layout).

Tests

pip install -r requirements-dev.txt
pytest

Python modules

Module Role
lucus.apps.LucusConfig ready(): headers, each_context, dashboard context, lucus_save_ui / lucus_save_site, enable_nav_sidebar, empty_value_display, ModelAdmin action defaults
lucus.dashboard Normalize LUCUS_DASHBOARD
lucus.models LucusAdminUiPreference
lucus.theme Bundled schemes, lucus_admin_extra_context
lucus.views POST handlers UI / site

If you use the header site switcher and want request.site on each request to match that choice, register lucus.sites_panel.LucusAdminSiteMiddleware immediately after SessionMiddleware. Setup details are in the lucus.sites_panel module.

This repo includes an integration/ demo app and requirements-integration.txt; optional pip install -e ".[integration]". Use the root manage.py with core.settings; some demos expect sorl.thumbnail to be installed.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_lucus-0.1.8.tar.gz (104.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_lucus-0.1.8-py3-none-any.whl (124.8 kB view details)

Uploaded Python 3

File details

Details for the file django_lucus-0.1.8.tar.gz.

File metadata

  • Download URL: django_lucus-0.1.8.tar.gz
  • Upload date:
  • Size: 104.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for django_lucus-0.1.8.tar.gz
Algorithm Hash digest
SHA256 f385b6c3343b52297ae0e0fe38b68498925813cc2721d0cd153072dbcace1b6f
MD5 ba2e0b3cd6d82f3051d9d0a40b46c286
BLAKE2b-256 3110076c47dc4e4f889435f66f2036bafbd3702632ffceb02b2369d82b021d2b

See more details on using hashes here.

File details

Details for the file django_lucus-0.1.8-py3-none-any.whl.

File metadata

  • Download URL: django_lucus-0.1.8-py3-none-any.whl
  • Upload date:
  • Size: 124.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for django_lucus-0.1.8-py3-none-any.whl
Algorithm Hash digest
SHA256 e8c0cd0b005653da0c7015eb996a09a9e385ff01fda4bcfc25863da4d982a903
MD5 3203fc08a3bfc23a128c8b49bc93a61b
BLAKE2b-256 0935cb740cf6e2ab36aad0891a3da9f5308ac0f84649e2e1b310ec0f2e86c2be

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page