Skip to main content

Modal-based related-object popups for django-unfold

Project description

Unfold modal preview

django-unfold-modal

PyPI - Version Build

Modal-based related-object popups for django-unfold.

Replaces Django admin's popup windows for related objects (ForeignKey, ManyToMany, etc.) with Unfold-styled modals.

Features

  • Modal replacement for admin related-object popups
  • Supports nested modals (replace/restore behavior)
  • Raw ID lookup + autocomplete + inline related fields
  • Optional modal resize + size presets
  • Optional admin header suppression inside iframe
  • Django CMS modal support (open admin modals in Django CMS parent window)
  • Stylable using Unfold theme configuration & custom CSS

Motivation

As much as I love the Django admin, I’ve always found its related-object pop-ups clunky and outdated. They open in separate browser windows, which breaks the flow and doesn’t fit modern UI patterns. It’s fine for straightforward admin use, but when exposed to users, it often causes confusion.

Django Unfold greatly improves the admin’s UX for regular users. This package modernizes related-object interactions while following Unfold’s design principles.

AI Disclaimer: Beyond the practical use of the package, the project was also driven by the incentive to explore AI-assisted research and development. All code was intentionally written by AI using structured, automated agent orchestration, including development and review by different models (Claude CLI Sonnet/Opus & Codex CLI), result verification, and regression testing.

Design and implementation decisions were made by me and reviewed/tested.

If interested in the process, see plans, tasks and reviews folder to get an idea of how the package was developed.

Requirements

  • Python 3.10+
  • Django 5.0+
  • django-unfold 0.52.0+ (tested with latest)

Installation

pip install django-unfold-modal

Add to your INSTALLED_APPS after unfold:

INSTALLED_APPS = [
    "unfold",
    "unfold.contrib.filters",
    "unfold_modal",  # Add after unfold, before django.contrib.admin
    "django.contrib.admin",
    # ...
]

Add the required styles and scripts to your Unfold configuration in settings.py:

Minimal setup:

from unfold_modal.utils import get_modal_styles, get_modal_scripts

UNFOLD = {
    # ... other unfold settings ...
    "STYLES": [
        *get_modal_styles(),
    ],
    "SCRIPTS": [
        *get_modal_scripts(),
    ],
}

This setup loads only the core modal scripts. If you do not use the configuration options below, this is enough.

Config-enabled setup (for custom sizes and resize handle):

from unfold_modal.utils import get_modal_styles, get_modal_scripts_with_config

UNFOLD = {
    # ... other unfold settings ...
    "STYLES": [
        *get_modal_styles(),
    ],
    "SCRIPTS": [
        *get_modal_scripts_with_config(),
    ],
}

This setup adds a config script (served from unfold_modal.urls) before the core JS so the frontend can read size presets and UNFOLD_MODAL_RESIZE. See Configuration below for the options that require it.

Configuration

The following settings are available (all optional):

# Content loading strategy: "iframe" (default, v1 only)
UNFOLD_MODAL_VARIANT = "iframe"

# Presentation style: "modal" (default, v1 only)
UNFOLD_MODAL_PRESENTATION = "modal"

# Modal size preset: "default", "large", or "full"
UNFOLD_MODAL_SIZE = "default"

# Enable manual resize handle on modal (default: False)
UNFOLD_MODAL_RESIZE = False

# Hide admin header inside modal iframes (default: True)
UNFOLD_MODAL_DISABLE_HEADER = True

Size Presets

To use custom size presets (UNFOLD_MODAL_SIZE) or enable resize (UNFOLD_MODAL_RESIZE):

  1. Include the app's URLs in your urls.py:

    from django.urls import include, path
    
    urlpatterns = [
        path("admin/", admin.site.urls),
        path("unfold-modal/", include("unfold_modal.urls")),
    ]
    
  2. Use get_modal_scripts_with_config instead of get_modal_scripts in your UNFOLD configuration (see Installation section above).

Preset Width Max Width Height Max Height
default 90% 900px 85vh 700px
large 95% 1200px 90vh 900px
full 98% none 95vh none

Django CMS Integration

When Django admin is embedded inside a Django CMS modal (e.g., editing a page plugin), unfold-modal can render its modals in the CMS parent document instead of inside the admin iframe.

How It Works

  • Admin inside a CMS sideframe iframe: modals open inside the iframe (standard behavior).
  • Admin inside a CMS modal iframe (.cms-modal): modals open in the CMS parent document for a seamless full-page experience.

Detection is automatic based on the presence of a .cms-modal ancestor in the parent DOM.

CMS Template Setup

Load the required assets in your CMS base template (e.g., a custom base.html extending CMS templates):

{% load unfold_modal_tags %}
<head>
    ...
    {% unfold_modal_cms_head %}
</head>

This outputs the Material Symbols icon font, modal CSS, inline config, and JS modules needed for CMS parent-window modal hosting. The icon font is required so modal controls (close, maximize) display as glyphs instead of plain text. The modal uses a high z-index (9999999) to render above Django CMS layers.

CMS Modal Settings

CMS modal settings are independent from regular admin modal settings. Defaults are optimized for CMS context (fullscreen):

# CMS modal size preset (default: "full")
UNFOLD_CMS_MODAL_SIZE = "full"

# Enable resize handle in CMS modal (default: False)
UNFOLD_CMS_MODAL_RESIZE = False

# Hide admin header inside CMS modal iframes (default: True)
UNFOLD_CMS_MODAL_DISABLE_HEADER = True

Regular UNFOLD_MODAL_* settings continue to apply to standard admin modal usage. CMS settings only affect modals opened from within a CMS modal context.

Supported Widgets

  • ForeignKey select
  • ManyToMany select
  • OneToOne select
  • raw_id_fields lookup
  • autocomplete_fields (Select2)
  • Related fields within inline forms

Testing

pytest -q
pytest --browser chromium

See tests/README.md for the test app overview and Playwright scope.

CI

GitHub Actions runs on all PRs and pushes to main/development:

  • Unit tests across Python 3.10, 3.11, 3.12
  • Playwright UI tests with Chromium

Configure branch protection to require the CI check to pass before merging.

License

MIT

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_unfold_modal-0.2.1.tar.gz (338.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_unfold_modal-0.2.1-py3-none-any.whl (23.8 kB view details)

Uploaded Python 3

File details

Details for the file django_unfold_modal-0.2.1.tar.gz.

File metadata

  • Download URL: django_unfold_modal-0.2.1.tar.gz
  • Upload date:
  • Size: 338.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: python-httpx/0.28.1

File hashes

Hashes for django_unfold_modal-0.2.1.tar.gz
Algorithm Hash digest
SHA256 fe3e7774da282a649174a5ef0567cb7f409506044e8eb616a2693bf537620c5d
MD5 7da1d6bf4f807fda96935e8112d82284
BLAKE2b-256 8a3ffda8f6098904d2a5e12d46f03a8278ed5b9a8f77560b766d082d74c4f5c6

See more details on using hashes here.

File details

Details for the file django_unfold_modal-0.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for django_unfold_modal-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 bd10d1458698bf189db7b048da7b5ed959a0da7a0288d95e06dea233688739dc
MD5 d717eef46127ea811bf8f996ae475627
BLAKE2b-256 a3ec7491220bd65229e92023a6ee04335d9ab893b403564c9a2f3bb4da861bbf

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