Package: django-bootstrap-modal-forms
A Django plugin for creating AJAX driven forms in Bootstrap modal.Table of ContentsLive DemoGeneral informationOpening an issueContributeTest and experiment on your machineTestsInstallationHow it works?Usage1. Form2. Form’s html3. Class-based view4. URL for the view5. Bootstrap modal and trigger element6. modalFormAsync create/update with or without modal closing on submitmodalForm optionsmodalForm default settings object and it’s structureFormsMixinsGeneric viewsExamplesExample 1: Signup form in Bootstrap modalExample 2: Login form in Bootstrap modalExample 3: Django’s forms.ModelForm (CRUD forms) in Bootstrap modalExample 4: Django’s forms.Form in Bootstrap modalLicenseLive DemoDemoGeneral informationOpening an issueWhen reporting an issue fordjango-bootstrap-modal-formspackage, please prepare a publicly available repository having the issue you are reporting. The clear reproduce is the optimal way towards resolution.ContributeThis is an Open Source project and any contribution is highly appreciated.Test and experiment on your machineThis repository includesDockerfileanddocker-compose.ymlfiles so you can easily setup and start to experiment withdjango-bootstrap-modal-formsrunning inside of a container on your local machine. Any changes you make inbootstrap_modal_forms,examplesandtestfolders are reflected in the container (see docker-compose.yml) and the data stored in sqlite3 database are persistent even if you remove stopped container. Follow the steps below to run the app:$ clone repository
$ cd django-bootstrap-modal-forms
$ docker compose up (use -d flag to run app in detached mode in the background)
$ visit 0.0.0.0:8000TestsRun unit and functional tests inside of project folder:$ python manage.py testInstallationInstalldjango-bootstrap-modal-forms:$ pip install django-bootstrap-modal-formsAddbootstrap_modal_formsto your INSTALLED_APPS in settings.py:INSTALLED_APPS = [
    ...
    'bootstrap_modal_forms',
    ...
]Include Bootstrap, jQuery andjquery.bootstrap(5).modal.forms.json every page where you would like to set up the AJAX driven Django forms in Bootstrap modal.IMPORTANT:Adjust Bootstrap and jQuery file paths to match yours, but includejquery.bootstrap.modal.forms.jsexactly as in code bellow.<head><linkrel="stylesheet"href="{%static'assets/css/bootstrap.css'%}"></head><body><scriptsrc="{%static'assets/js/bootstrap.js'%}"></script><!-- Bootstrap 4 --><scriptsrc="{%static'assets/js/jquery-3.2.1.min.js'%}"></script><scriptsrc="{%static'assets/js/popper.min.js'%}"></script><scriptsrc="{%static'assets/js/bootstrap.min.js'%}"></script><!-- You can alternatively load the minified version --><scriptsrc="{%static'js/jquery.bootstrap.modal.forms.js'%}"></script><!-- Bootstrap 5 --><scriptsrc="{%static'assets/js/bootstrap.bundle.min.js'%}"></script><scriptsrc="{%static'js/bootstrap5.modal.forms.js'%}"></script><!-- You can alternatively load the minified version --><scriptsrc="{%static'js/bootstrap5.modal.forms.min.js'%}"></script></body>How it works?index.html<scripttype="text/javascript">// BS4$(document).ready(function(){$("#create-book").modalForm({formURL:"{% url 'create_book' %}"});});// BS5// instantiate single modal formdocument.addEventListener('DOMContentLoaded',(e)=>{modalForm(document.getElementById('create-book'),{formURL:"{% url 'create_book' %}"})});// BS5// instantiate multiple modal forms with unique formUrlsdocument.addEventListener('DOMContentLoaded',(e)=>{vardeleteButtons=document.getElementsByClassName("delete-book");for(varindex=0;index<deleteButtons.length;index++){modalForm(deleteButtons[index],{formURL:deleteButtons[index]["dataset"]["formUrl"],isDeleteForm:true});}});</script>Click event on html element instantiated withmodalFormopens modalForm atformURLis appended to the modalOn submit the form is POSTed via AJAX request toformURLUnsuccessful POST requestreturns errors, which are shown in modalSuccessful POST requestsubmits the form and redirects tosuccess_urland showssuccess_message, which are both defined in related Django viewUsage1. FormDefine BookModelForm and inherit built-in formBSModalModelForm.forms.pyfrom.modelsimportBookfrombootstrap_modal_forms.formsimportBSModalModelFormclassBookModelForm(BSModalModelForm):classMeta:model=Bookfields=['title','author','price']2. Form’s htmlDefine form’s html and save it as Django template.Bootstrap 4 modal elements are used in this example.Form will POST toformURLdefined in #6.Addclass="invalid"or customerrorClass(see paragraphOptions) to the elements that wrap the fields.class="invalid"acts as a flag for the fields having errors after the form has been POSTed.book/create_book.html<formmethod="post"action="">{% csrf_token %}<divclass="modal-header"><h5class="modal-title">Create new Book</h5><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body">{% for field in form %}<divclass="form-group{% if field.errors %} invalid{% endif %}"><labelfor="{{ field.id_for_label }}">{{ field.label }}</label>{{ field }}
        {% for error in field.errors %}<pclass="help-block">{{ error }}</p>{% endfor %}</div>{% endfor %}</div><divclass="modal-footer"><buttontype="button"class="btn btn-default"data-dismiss="modal">Close</button><buttontype="submit"class="btn btn-primary">Create</button></div></form>3. Class-based viewDefine a class-based view BookCreateView and inherit from built-in generic viewBSModalCreateView. BookCreateView processes the form defined in #1, uses the template defined in #2 and redirects tosuccess_urlshowingsuccess_message.views.pyfromdjango.urlsimportreverse_lazyfrom.formsimportBookModelFormfrom.modelsimportBookfrombootstrap_modal_forms.genericimportBSModalCreateViewclassBookCreateView(BSModalCreateView):template_name='examples/create_book.html'form_class=BookModelFormsuccess_message='Success: Book was created.'success_url=reverse_lazy('index')4. URL for the viewDefine URL for the view in #3.fromdjango.urlsimportpathfrombooksimportviewsurlpatterns=[path('',views.Index.as_view(),name='index'),path('create/',views.BookCreateView.as_view(),name='create_book'),]5. Bootstrap modal and trigger elementDefine the Bootstrap modal window and html element triggering modal opening.Single modalcan be used for multiplemodalFormsin single template (see #6).When usingmultiple modalson the same page each modal should have uniqueidand the same value should also be set asmodalIDoption when instantiatingmodalFormon trigger element.Trigger element (in this example button withid="create-book") is used for instantiation ofmodalFormin #6.Any element can be trigger element as long asmodalFormis bound to it.Click event on trigger element loads form’s html from #2 within<divclass="modal-content"></div>and sets action attribute of the form toformURLset in #6.index.html<divclass="modal fade"tabindex="-1"role="dialog"id="modal"><divclass="modal-dialog"role="document"><divclass="modal-content"></div></div></div><!-- Create book button --><buttonid="create-book"class="btn btn-primary"type="button"name="button">Create book</button>6. modalFormAdd script to the template from #5 and bind themodalFormto the trigger element. Set BookCreateView URL defined in #4 asformURLproperty ofmodalForm.If you want to createmore modalForms in single template using the single modal windowfrom #5, repeat steps #1 to #4, create new trigger element as in #5 and bind the newmodalFormwith unique URL to it.Default values formodalID,modalContent,modalFormanderrorClassare used in this example, whileformURLis customized. If you customize any other option adjust the code of the above examples accordingly.index.html<scripttype="text/javascript">// BS4$(document).ready(function(){$("#create-book").modalForm({formURL:"{% url 'create_book' %}"});});// BS5document.addEventListener('DOMContentLoaded',(e)=>{modalForm(document.getElementById('create-book'),{formURL:"{% url 'create_book' %}"})});</script>Async create/update with or without modal closing on submitSetasyncUpdateandasyncSettingssettings to create or update objects without page redirection tosuccessUrland define whether a modal should close or stay opened after form submission. See comments in example below and paragraphmodalForm optionsfor explanation ofasyncSettings.
See examples on how to properly reinstantiate modal forms for all CRUD buttons when using async options.index.html<!-- asyncSettings.dataElementId --><tableid="books-table"class="table"><thead>...</thead><tbody>{% for book in books %}<tr>...<!-- Update book buttons --><buttontype="button"class="update-book btn btn-sm btn-primary"data-form-url="{% url 'update_book' book.pk %}"><spanclass="fa fa-pencil"></span></button>...</td></tr>{% endfor %}</tbody></table><scripttype="text/javascript">$(function(){...#asyncSettings.successMessagevarasyncSuccessMessage=["<div ","style='position:fixed;top:0;z-index:10000;width:100%;border-radius:0;' ","class='alert alert-icon alert-success alert-dismissible fade show mb-0' role='alert'>","Success: Book was updated.","<button type='button' class='close' data-dismiss='alert' aria-label='Close'>","<span aria-hidden='true'>&times;</span>","</button>","</div>","<script>","$('.alert').fadeTo(2000, 500).slideUp(500, function () {$('.alert').slideUp(500).remove();});","<\/script>"].join();#asyncSettings.addModalFormFunctionfunctionupdateBookModalForm(){$(".update-book").each(function(){$(this).modalForm({formURL:$(this).data("form-url"),asyncUpdate:true,asyncSettings:{closeOnSubmit:false,successMessage:asyncSuccessMessagedataUrl:"books/",dataElementId:"#books-table",dataKey:"table",addModalFormFunction:updateBookModalForm}});});}updateBookModalForm();...});</script>urls.pyfromdjango.urlsimportpathfrom.importviewsurlpatterns=[...# asyncSettings.dataUrlpath('books/',views.books,name='books'),...]views.pyfromdjango.httpimportJsonResponsefromdjango.template.loaderimportrender_to_stringfrom.modelsimportBookdefbooks(request):data=dict()ifrequest.method=='GET':books=Book.objects.all()# asyncSettings.dataKey = 'table'data['table']=render_to_string('_books_table.html',{'books':books},request=request)returnJsonResponse(data)modalForm optionsmodalIDSets the custom id of the modal.Default: "#modal"modalContentSets the custom class of the element to which the form’s html is appended. If you changemodalContentto the custom class, you should also changemodalFormaccordingly. To keep Bootstrap’s modal style you should than copy Bootstrap’s style formodal-contentand set it to your new modalContent class.Default:".modal-content"modalFormSets the custom form selector.Default:".modal-contentform"formURLSets the url of the form’s view and html.Default: nullisDeleteFormDefines if form is used for deletion. Should be set totruefor deletion forms.Default: falseerrorClassSets the custom class for the form fields having errors.Default: ".invalid"asyncUpdateSets asynchronous content update after form submission.Default: falseasyncSettings.closeOnSubmitSets whether modal closes or not after form submission.Default: falseasyncSettings.successMessageSets successMessage shown after succesful for submission. Should be set to string defining message element. SeeasyncSuccessMessageexample above.Default: nullasyncSettings.dataUrlSets url of the view returning new queryset = all of the objects plus newly created or updated one after asynchronous update.Default: nullasyncSettings.dataElementIdSets theidof the element which rerenders asynchronously updated queryset.Default: nullasyncSettings.dataKeySets the key containing asynchronously updated queryset in the data dictionary returned from the view providing updated queryset.Default: nullasyncSettings.addModalFormFunctionSets the method needed for reinstantiation of event listeners on buttons (single or all CRUD buttons) after asynchronous update.Default: nullmodalForm default settings object and it’s structuretriggerElement.modalForm({
    modalID: "#modal",
    modalContent: ".modal-content",
    modalForm: ".modal-content form",
    formURL: null,
    isDeleteForm: false,
    errorClass: ".invalid",
    asyncUpdate: false,
    asyncSettings: {
        closeOnSubmit: false,
        successMessage: null,
        dataUrl: null,
        dataElementId: null,
        dataKey: null,
        addModalFormFunction: null
    }
});FormsImport forms withfrom bootstrap_modal_forms.forms import BSModalForm.BSModalFormInherits PopRequestMixin and Django’s forms.Form.BSModalModelFormInherits PopRequestMixin, CreateUpdateAjaxMixin and Django’s forms.ModelForm.MixinsImport mixins withfrom bootstrap_modal_forms.mixins import PassRequestMixin.PassRequestMixinForm Mixin which puts the request into the form’s kwargs. Note: Using this mixin requires you to pop therequestkwarg out of the dict in the super of your form’s__init__. See PopRequestMixin.PopRequestMixinForm Mixin which pops request out of the kwargs and attaches it to the form’s instance. Note: This mixin must precede forms.ModelForm/forms.Form. The form is not expecting these kwargs to be passed in, so they must be popped off before anything else is done.CreateUpdateAjaxMixinModelForm Mixin which passes or saves object based on request type.DeleteMessageMixinGeneric View Mixin which adds message to BSModalDeleteView and only calls the post method if request is not ajax request. In case request is ajax post method calls delete method, which redirects to success url.FormValidationMixinGeneric View Mixin which saves object and redirects to success_url if request is not ajax request. Otherwise response 204 No content is returned.LoginAjaxMixinGeneric View Mixin which authenticates user if request is not ajax request.Generic viewsImport generic views withfrom bootstrap_modal_forms.generic import BSModalFormView.BSModalLoginViewInhertis LoginAjaxMixin and Django’s LoginView.BSModalFormViewInherits PassRequestMixin and Django’s generic.FormView.BSModalCreateViewInherits PassRequestMixin, FormValidationMixin and generic.CreateView.BSModalUpdateViewInherits PassRequestMixin, FormValidationMixin and generic.UpdateView.BSModalReadViewInherits Django’s generic.DetailView.BSModalDeleteViewInherits DeleteMessageMixin and Django’s generic.DeleteView.ExamplesTo seedjango-bootstrap-modal-formsin action clone the repository and run the examples locally:$ git clone https://github.com/trco/django-bootstrap-modal-forms.git
$ cd django-bootstrap-modal-forms
$ pip install -r requirements.txt
$ python manage.py migrate
$ python manage.py runserverExample 1: Signup form in Bootstrap modalFor explanation how all the parts of the code work together see paragraphUsage. To test the working solution presented here clone and runExamples.forms.pyfromdjango.contrib.auth.formsimportUserCreationFormfromdjango.contrib.auth.modelsimportUserfrombootstrap_modal_forms.mixinsimportPopRequestMixin,CreateUpdateAjaxMixinclassCustomUserCreationForm(PopRequestMixin,CreateUpdateAjaxMixin,UserCreationForm):classMeta:model=Userfields=['username','password1','password2']signup.html

{% load widget_tweaks %}<formmethod="post"action="">{% csrf_token %}<divclass="modal-header"><h3class="modal-title">Sign up</h3><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body"><divclass="{% if form.non_field_errors %}invalid{% endif %} mb-2">{% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}</div>{% for field in form %}<divclass="form-group"><labelfor="{{ field.id_for_label }}">{{ field.label }}</label>{% render_field field class="form-control" placeholder=field.label %}<divclass="{% if field.errors %} invalid{% endif %}">{% for error in field.errors %}<pclass="help-block">{{ error }}</p>{% endfor %}</div></div>{% endfor %}</div><divclass="modal-footer"><buttontype="submit"class="btn btn-primary">Sign up</button></div></form>views.pyfromdjango.urlsimportreverse_lazyfrombootstrap_modal_forms.genericimportBSModalCreateViewfrom.formsimportCustomUserCreationFormclassSignUpView(BSModalCreateView):form_class=CustomUserCreationFormtemplate_name='examples/signup.html'success_message='Success: Sign up succeeded. You can now Log in.'success_url=reverse_lazy('index')urls.pyfromdjango.urlsimportpathfrom.importviewsapp_name='accounts'urlpatterns=[path('signup/',views.SignUpView.as_view(),name='signup')].html file containing modal, trigger element and script instantiating modalForm<divclass="modal fade"tabindex="-1"role="dialog"id="modal"><divclass="modal-dialog"role="document"><divclass="modal-content"></div></div></div><buttonid="signup-btn"class="btn btn-primary"type="button"name="button">Sign up</button><scripttype="text/javascript">$(function(){// Sign up button$("#signup-btn").modalForm({formURL:"{% url 'signup' %}"});});</script>Example 2: Login form in Bootstrap modalFor explanation how all the parts of the code work together see paragraphUsage. To test the working solution presented here clone and runExamples.You can set the login redirection by setting theLOGIN_REDIRECT_URLinsettings.py.You can also set the custom login redirection by:Addingsuccess_urlto theextra_contextofCustomLoginViewSetting thissuccess_urlvariable as a value of thehidden input fieldwithname="next"within the Login form htmlforms.pyfromdjango.contrib.auth.formsimportAuthenticationFormfromdjango.contrib.auth.modelsimportUserclassCustomAuthenticationForm(AuthenticationForm):classMeta:model=Userfields=['username','password']login.html

{% load widget_tweaks %}<formmethod="post"action="">{% csrf_token %}<divclass="modal-header"><h3class="modal-title">Log in</h3><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body"><divclass="{% if form.non_field_errors %}invalid{% endif %} mb-2">{% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}</div>{% for field in form %}<divclass="form-group"><labelfor="{{ field.id_for_label }}">{{ field.label }}</label>{% render_field field class="form-control" placeholder=field.label %}<divclass="{% if field.errors %} invalid{% endif %}">{% for error in field.errors %}<pclass="help-block">{{ error }}</p>{% endfor %}</div></div>{% endfor %}<!-- Hidden input field for custom redirection after successful login --><inputtype="hidden"name="next"value="{{ success_url }}"></div><divclass="modal-footer"><buttontype="submit"class="btn btn-primary">Log in</button></div></form>views.pyfromdjango.urlsimportreverse_lazyfrombootstrap_modal_forms.genericimportBSModalLoginViewfrom.formsimportCustomAuthenticationFormclassCustomLoginView(BSModalLoginView):authentication_form=CustomAuthenticationFormtemplate_name='examples/login.html'success_message='Success: You were successfully logged in.'extra_context=dict(success_url=reverse_lazy('index'))urls.pyfromdjango.urlsimportpathfrom.importviewsapp_name='accounts'urlpatterns=[path('login/',views.CustomLoginView.as_view(),name='login')].html file containing modal, trigger element and script instantiating modalForm<divclass="modal fade"tabindex="-1"role="dialog"id="modal"><divclass="modal-dialog"role="document"><divclass="modal-content"></div></div></div><buttonid="login-btn"class="btn btn-primary"type="button"name="button">Sign up</button><scripttype="text/javascript">$(function(){// Log in button$("#login-btn").modalForm({formURL:"{% url 'login' %}"});});</script>Example 3: Django’s forms.ModelForm (CRUD forms) in Bootstrap modalFor explanation how all the parts of the code work together see paragraphUsage. To test the working solution presented here clone and runExamples.forms.pyfrom.modelsimportBookfrombootstrap_modal_forms.formsimportBSModalModelFormclassBookModelForm(BSModalModelForm):classMeta:model=Bookexclude=['timestamp']create_book.html

{% load widget_tweaks %}<formmethod="post"action="">{% csrf_token %}<divclass="modal-header"><h3class="modal-title">Create Book</h3><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body"><divclass="{% if form.non_field_errors %}invalid{% endif %} mb-2">{% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}</div>{% for field in form %}<divclass="form-group"><labelfor="{{ field.id_for_label }}">{{ field.label }}</label>{% render_field field class="form-control" placeholder=field.label %}<divclass="{% if field.errors %} invalid{% endif %}">{% for error in field.errors %}<pclass="help-block">{{ error }}</p>{% endfor %}</div></div>{% endfor %}</div><divclass="modal-footer"><buttontype="submit"class="btn btn-primary">Create</button></div></form>update_book.html

{% load widget_tweaks %}<formmethod="post"action="">{% csrf_token %}<divclass="modal-header"><h3class="modal-title">Update Book</h3><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body"><divclass="{% if form.non_field_errors %}invalid{% endif %} mb-2">{% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}</div>{% for field in form %}<divclass="form-group"><labelfor="{{ field.id_for_label }}">{{ field.label }}</label>{% render_field field class="form-control" placeholder=field.label %}<divclass="{% if field.errors %} invalid{% endif %}">{% for error in field.errors %}<pclass="help-block">{{ error }}</p>{% endfor %}</div></div>{% endfor %}</div><divclass="modal-footer"><buttontype="submit"class="btn btn-primary">Update</button></div></form>read_book.html

{% load widget_tweaks %}<divclass="modal-header"><h3class="modal-title">Book details</h3><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body"><divclass="">Title: {{ book.title }}</div><divclass="">Author: {{ book.author }}</div><divclass="">Price: {{ book.price }} €</div></div><divclass="modal-footer"><buttontype="button"class="btn btn-default"data-dismiss="modal">Close</button></div>{% load widget_tweaks %}<formmethod="post"action="">{% csrf_token %}<divclass="modal-header"><h3class="modal-title">Delete Book</h3><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body"><p>Are you sure you want to delete book with title<strong>{{ book.title }}</strong>?</p></div><divclass="modal-footer"><buttontype="submit"class="btn btn-danger">Delete</button></div></form>views.pyfromdjango.urlsimportreverse_lazyfromdjango.viewsimportgenericfrom.formsimportBookModelFormfrom.modelsimportBookfrombootstrap_modal_forms.genericimport(BSModalCreateView,BSModalUpdateView,BSModalReadView,BSModalDeleteView)classIndex(generic.ListView):model=Bookcontext_object_name='books'template_name='index.html'# CreateclassBookCreateView(BSModalCreateView):template_name='examples/create_book.html'form_class=BookModelFormsuccess_message='Success: Book was created.'success_url=reverse_lazy('index')# UpdateclassBookUpdateView(BSModalUpdateView):model=Booktemplate_name='examples/update_book.html'form_class=BookModelFormsuccess_message='Success: Book was updated.'success_url=reverse_lazy('index')# ReadclassBookReadView(BSModalReadView):model=Booktemplate_name='examples/read_book.html'# DeleteclassBookDeleteView(BSModalDeleteView):model=Booktemplate_name='examples/delete_book.html'success_message='Success: Book was deleted.'success_url=reverse_lazy('index')urls.pyfromdjango.urlsimportpathfrombooksimportviewsurlpatterns=[path('',views.Index.as_view(),name='index'),path('create/',views.BookCreateView.as_view(),name='create_book'),path('update/<int:pk>',views.BookUpdateView.as_view(),name='update_book'),path('read/<int:pk>',views.BookReadView.as_view(),name='read_book'),path('delete/<int:pk>',views.BookDeleteView.as_view(),name='delete_book')].html file containing modal, trigger elements and script instantiating modalForms<!-- Modal 1 with id="create-book"--><divclass="modal fade"id="create-modal"tabindex="-1"role="dialog"aria-hidden="true"><divclass="modal-dialog"><divclass="modal-content"></div></div></div><!-- Modal 2 with id="modal" --><divclass="modal fade"tabindex="-1"role="dialog"id="modal"><divclass="modal-dialog"role="document"><divclass="modal-content"></div></div></div><!-- Create book button --><buttonid="create-book"class="btn btn-primary"type="button"name="button">Create book</button>{% for book in books %}<divclass="text-center"><!-- Read book buttons --><buttontype="button"class="read-book bs-modal btn btn-sm btn-primary"data-form-url="{% url 'read_book' book.pk %}"><spanclass="fa fa-eye"></span></button><!-- Update book buttons --><buttontype="button"class="update-book bs-modal btn btn-sm btn-primary"data-form-url="{% url 'update_book' book.pk %}"><spanclass="fa fa-pencil"></span></button><!-- Delete book buttons --><buttontype="button"class="delete-book bs-modal btn btn-sm btn-danger"data-form-url="{% url 'delete_book' book.pk %}"><spanclass="fa fa-trash"></span></button></div>{% endfor %}<scripttype="text/javascript">$(function(){// Read book buttons$(".read-book").each(function(){$(this).modalForm({formURL:$(this).data("form-url")});});// Delete book buttons - formURL is retrieved from the data of the element$(".delete-book").each(function(){$(this).modalForm({formURL:$(this).data("form-url"),isDeleteForm:true});});// Create book button opens form in modal with id="create-modal"$("#create-book").modalForm({formURL:"{% url 'create_book' %}",modalID:"#create-modal"});});</script>See the difference between button triggering Create action and buttons triggering Read, Update and Delete actions.Within the for loop in .html file thedata-form-urlattribute of each Update, Read and Delete button should be set to relevant URL with pk argument of the object to be updated, read or deleted.Thesedata-form-urlURLs should than be set asformURLsformodalFormsbound to the buttons.Example 4: Django’s forms.Form in Bootstrap modalFor explanation how all the parts of the code work together see paragraphUsage. To test the working solution presented here clone and runExamples.forms.pyfrombootstrap_modal_forms.formsimportBSModalFormclassBookFilterForm(BSModalForm):type=forms.ChoiceField(choices=Book.BOOK_TYPES)classMeta:fields=['type']filter_book.html

{% load widget_tweaks %}<formmethod="post"action="">{% csrf_token %}<divclass="modal-header"><h3class="modal-title">Filter Books</h3><buttontype="button"class="close"data-dismiss="modal"aria-label="Close"><spanaria-hidden="true">&times;</span></button></div><divclass="modal-body"><divclass="{% if form.non_field_errors %}invalid{% endif %} mb-2">{% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}</div>{% for field in form %}<divclass="form-group"><labelfor="{{ field.id_for_label }}">{{ field.label }}</label>{% render_field field class="form-control" placeholder=field.label %}<divclass="{% if field.errors %} invalid{% endif %}">{% for error in field.errors %}<pclass="help-block">{{ error }}</p>{% endfor %}</div></div>{% endfor %}</div><divclass="modal-footer"><buttontype="submit"class="btn btn-primary">Filter</button></div></form>views.pyclassBookFilterView(BSModalFormView):template_name='examples/filter_book.html'form_class=BookFilterFormdefform_valid(self,form):self.filter='?type='+form.cleaned_data['type']response=super().form_valid(form)returnresponsedefget_success_url(self):returnreverse_lazy('index')+self.filterurls.pyfromdjango.urlsimportpathfrom.importviewsapp_name='accounts'urlpatterns=[path('filter/',views.BookFilterView.as_view(),name='filter_book'),]index.html

  ...<buttonid="filter-book"class="filter-book btn btn-primary"type="button"name="button"data-form-url="{% url 'filter_book' %}"><spanclass="fa fa-filter mr-2"></span>Filter books</button>...<scripttype="text/javascript">$(function(){...$("#filter-book").each(function(){$(this).modalForm({formURL:$(this).data('form-url')});});...});</script>LicenseThis project is licensed under the MIT License.