django-crisp-modals
django-crisp-modals is a Django app which provides support for ajax Django Crispy Forms inside Bootstrap 5 modal dialogs. The app provides various views, form classes, templates and javascript. A demo site showcasing an example configuration various features, is available in the repository.
Quick start
-
Add "crisp_modals", and "crispy_forms" to your INSTALLED_APPS setting like this::
INSTALLED_APPS = [ ..., "crispy_forms", "crispy_bootstrap5", "crisp_modals", ]
-
Add the following to your settings.py file::
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" CRISPY_TEMPLATE_PACK = "bootstrap5"
-
Include the
crisp_modals/modals.min.jswithin your base template after jQuery and add a blank modal div to the bottom of the body tag. The modal div should have the id:modal-target. Then initialize the modal target. For example:{% load static %} ... <div id="modal-target"></div> <script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/jquery-form@4.3.0/dist/jquery.form.min.js"></script> <script src="{% static 'crisp_modals/modals.min.js' %}"></script> <script> $(document).ready(function() { $('#modal-target').initModal({ setup: function (element) { // This function is called for each modal that is opened. // You can add any additional setup code here. ... } }); }); </script> -
Create forms as follows. The main crispy-forms helper is available as
self.bodywithin the forms. A footer helper is also available asself.footer, with 'submit' and 'reset' buttons already included. To override the footer buttons, you can use theself.footer.clear()method to remove the default buttons and then add your own.from crisp_modals.forms import ModalModelForm, Row, FullWidth class PollForm(ModalModelForm): class Meta: model = Poll fields = ['question', 'pub_date'] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.body.append( Row( FullWidth('question', placeholder='Enter your question'), ), Row( FullWidth('pub_date', placeholder='Enter the publication date'), ) )
-
In your views, use the ModalCreateView, ModalUpdateView, ModalConfirmView, and ModalDeleteView classes as follows. Include
delete_urlin the form kwargs for the ModalUpdateView class to show the delete button within the form. By default, the form will be submitted to the same URL as the view, but you can override this by adding aform_actionvariable to the form keyword arguments.from crisp_modals.views import ModalCreateView, ModalUpdateView, ModalDeleteView class PollCreateView(ModalCreateView): model = Poll form_class = PollForm class PollEditView(ModalUpdateView): model = Poll form_class = PollForm def get_form_kwargs(self): kwargs = super().get_form_kwargs() # If you want the form submitted to a different url, override the `form_action` variable. kwargs['form_action'] = ... # e.g., reverse('polls:poll-update', kwargs={'pk': self.object.pk}) return kwargs def get_delete_url(self): # If you want to show a delete button in the form, you can return the URL for the delete confirmation view. return reverse('polls:poll-delete', kwargs={'pk': self.object.pk}) class PollConfirView(ModalConfirmView): model = Poll def get_context_data(self): context = super().get_context_data() context['title'] = 'Close Poll' context['message'] = 'Are you sure you want to close this poll?' return context def confirmed(self, *args, **kwargs): # Logic to close the poll self.object.close() # Assuming the Poll model has a close method return super().confirmed() class PollDeleteView(ModalDeleteView): model = Poll
-
To distinguish regular links from links that target modals, use the 'data-modal-url' attribute instead of href. For example:
<a href="#0" data-modal-url="{% url 'polls:poll-create' %}" class="modal-link">Create Poll</a> <a href="#0" data-modal-url="{% url 'polls:poll-update' pk=poll.pk %}">Update Poll</a>
Note:
The
data-modal-urlattribute should contain the url of the view that will render the modal. It doesn't have to return a form. Non-form modal content can be rendered by overriding themodal_contentblock in the modal templatecrisp_modals/modal.html. The following blocks are available for overriding:modal_header,modal_body,modal_footer,modal_scripts. Themodal_scriptsblock should be used to include any additional JavaScript required for the modal content per-instance. Any code needed for all modals should go in theinitModalsetup option.
Metadata
Release files for django-crisp-modals 2026.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_crisp_modals-2026.1.2.tar.gz | 13.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_crisp_modals-2026.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.2 kB
Release files / django_crisp_modals-2026.1.2.tar.gz
| Download URL | django_crisp_modals-2026.1.2.tar.gz |
|---|---|
| Size | 13.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
73ebb480c6af4d95da2aeb89efc0f4329431544147e01553cba5ef4f7190854a
|
|
BLAKE2b-256 checksum How to use checksums |
f75625230380f7af5e96ea4b345f6eeb799531e920f76a9369ed3953bad66423
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.3.4 CPython/3.14.7 Linux/7.1.8-200.fc44.x86_64
|
Release files / django_crisp_modals-2026.1.2-py3-none-any.whl
| Download URL | django_crisp_modals-2026.1.2-py3-none-any.whl |
|---|---|
| Size | 17.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2935c5fce17865f640865fc4a611f1b4e98f2a843b797d19f2242a54aff5aeb0
|
|
BLAKE2b-256 checksum How to use checksums |
edaa5c3c9e5e4033f2899a4093b197c83b8c3bad534705efd2a480ce63bf78ea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.3.4 CPython/3.14.7 Linux/7.1.8-200.fc44.x86_64
|