Modal-based related-object popups for django-unfold
Project description
django-unfold-modal
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
- 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: My goal was to research agentic capabilities in the development process of this package. 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
Naming: Install name is
django-unfold-modal, import/app name isunfold_modal— mirroring thedjango-unfold/unfoldpattern.
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):
-
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")), ]
-
Use
get_modal_scripts_with_configinstead ofget_modal_scriptsin 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 |
Supported Widgets
- ForeignKey select
- ManyToMany select
- OneToOne select
raw_id_fieldslookupautocomplete_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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_unfold_modal-0.1.0.tar.gz.
File metadata
- Download URL: django_unfold_modal-0.1.0.tar.gz
- Upload date:
- Size: 320.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c09d43da0d33470642525cd7e17f4ff936fc3f7656b075a113edf5443727ac56
|
|
| MD5 |
a3c78a511ca8da0c2a9d8d3f5ca683a7
|
|
| BLAKE2b-256 |
e09a8f806a6070ec4404a91278598fa7cd54885120b5c541f1ead1de470cb534
|
File details
Details for the file django_unfold_modal-0.1.0-py3-none-any.whl.
File metadata
- Download URL: django_unfold_modal-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: python-httpx/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af953e76dad190127e9b9ce0800673f1f9e2299d697f8f2cb1d90893afb18305
|
|
| MD5 |
1d2fcea38af94be2b36c4c65221a1e56
|
|
| BLAKE2b-256 |
99f1968da93f400b6ef21e5784f7bb9090860ae9e9ad65f9e222a425410b433e
|