Skip to main content

Modal components

Added in 1.0.7

AdminModal provides a reusable, permission-aware dialog inside any Chassis Admin page. The shell is rendered once, while each modal fragment is fetched only after its trigger is activated.

Define and register a modal

from django.http import HttpRequest, HttpResponse

from django_chassis.components import PermissionAdminModal
from django_chassis.options import PermissionOption


class ReconcileModal(PermissionAdminModal):
slug = 'reconcile'
title = 'Reconcile records'
template_name = 'admin/project/reconcile_modal.html'
permission = PermissionOption(
app_label='operations',
model='reconciliation',
codename='view_reconciliation',
name='Can view reconciliation'
)

def view(self, request: HttpRequest) -> HttpResponse:
return self.render(request=request, form=ReconcileForm())


class CustomAdminSite(ChassisAdminSiteMixin, AdminSite):
chassis_modal_classes = (ReconcileModal,)

PermissionAdminModal registers its PermissionOption and checks it both when Chassis builds the trigger context and when the fragment endpoint handles GET or POST. Use AdminModal directly when visibility needs a custom has_view_permission() implementation.

Render a trigger

Load chassis_admin in any Admin template:

{% load chassis_admin %}
{% chassis_modal_trigger "reconcile" "Open reconciliation" "fa-solid fa-scale-balanced" %}

The optional fourth argument sets the trigger CSS class. A trigger is omitted when its modal is unavailable to the current user.

Navbar dropdown children can open the same dialog by returning an AdminNavbarChildItemDTO with opens_modal=True and the modal URL.

Fragment template and forms

Extend the shared fragment and mark forms for asynchronous submission:

{% extends "admin/chassis/modal.html" %}

{% block chassis_modal_body %}
<p class="chassis-modal-description">Review the data before continuing.</p>
{% include "admin/chassis/modal_form_errors.html" %}
<form method="post" action="{{ chassis_modal.get_url }}" data-chassis-modal-form>
{% csrf_token %}
{{ form.as_p }}
<div class="chassis-modal-actions">
<button type="button" data-chassis-modal-close>Cancel</button>
<button type="submit">Continue</button>
</div>
</form>
{% endblock %}

Use AdminModal.redirect(url) after a successful POST. Chassis follows the redirect without an intermediate page request, preserving Django messages.

close_on_backdrop and close_on_escape default to True and can be configured independently. The modal shell and scrollable table helpers are bounded by the browser viewport.

Security contract

Modal endpoints are wrapped with AdminSite.admin_view(), require the X-Chassis-Modal: 1 request header, and re-run has_view_permission() on every request. Calling an endpoint directly therefore returns HTTP 400 rather than rendering a standalone Admin page.

See also