{"id":14972207,"url":"https://github.com/trco/django-bootstrap-modal-forms","last_synced_at":"2025-05-14T15:12:08.916Z","repository":{"id":37458278,"uuid":"135071231","full_name":"trco/django-bootstrap-modal-forms","owner":"trco","description":"A Django plugin for creating AJAX driven forms in Bootstrap modal.","archived":false,"fork":false,"pushed_at":"2024-12-06T19:34:14.000Z","size":970,"stargazers_count":382,"open_issues_count":26,"forks_count":143,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-05-12T19:09:11.306Z","etag":null,"topics":["ajax","bootstrap-modal","bootstrap3","bootstrap4","bootstrap5","django","form","jquery","modal","modal-form","modal-forms","popup","popup-form-with-validation"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trco.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-27T18:24:54.000Z","updated_at":"2025-05-03T13:07:56.000Z","dependencies_parsed_at":"2024-06-18T15:17:08.694Z","dependency_job_id":"8374f788-9a1e-4556-8f63-bcb6fb9f0248","html_url":"https://github.com/trco/django-bootstrap-modal-forms","commit_stats":{"total_commits":183,"total_committers":11,"mean_commits":"16.636363636363637","dds":"0.21311475409836067","last_synced_commit":"dbb3555d097f393f0d580e721061e80b77f23608"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trco%2Fdjango-bootstrap-modal-forms","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trco%2Fdjango-bootstrap-modal-forms/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trco%2Fdjango-bootstrap-modal-forms/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trco%2Fdjango-bootstrap-modal-forms/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trco","download_url":"https://codeload.github.com/trco/django-bootstrap-modal-forms/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254170067,"owners_count":22026219,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ajax","bootstrap-modal","bootstrap3","bootstrap4","bootstrap5","django","form","jquery","modal","modal-form","modal-forms","popup","popup-form-with-validation"],"created_at":"2024-09-24T13:46:33.350Z","updated_at":"2025-05-14T15:12:08.867Z","avatar_url":"https://github.com/trco.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"============================\nDjango Bootstrap Modal Forms\n============================\n\nA Django plugin for creating AJAX driven forms in Bootstrap modal.\n\n.. contents:: **Table of Contents**\n   :depth: 2\n   :local:\n   :backlinks: none\n\nTest and experiment on your machine\n===================================\n\nThis repository includes ``Dockerfile`` and ``docker-compose.yml`` files so you can easily setup and start to experiment with ``django-bootstrap-modal-forms`` running inside of a container on your local machine. Any changes you make in ``bootstrap_modal_forms``, ``examples`` and ``test`` folders are reflected in the container (see docker-compose.yml) and the data stored in sqlite3 database are persistent even if you remove stopped container.\n\nNote that ``master branch`` contains Bootstrap 4 examples, while ``bootstrap5-examples branch`` contains Bootstrap 5 examples. To experiment with Bootstrap 5 examples simply switch the branch.\n\nFollow the steps below to run the app::\n\n    $ clone repository\n    $ cd django-bootstrap-modal-forms\n    $ docker compose up (use -d flag to run app in detached mode in the background)\n    $ visit 0.0.0.0:8000\n\nGeneral information\n===================\n\nOpening an issue\n****************\nWhen reporting an issue for ``django-bootstrap-modal-forms`` package, please prepare a publicly available repository having the issue you are reporting. The clear reproduce is the optimal way towards resolution.\n\nContribute\n**********\nThis is an Open Source project and any contribution is highly appreciated.\n\nTests\n=====\n\nRun unit and functional tests inside of project folder::\n\n    $ python manage.py test\n\nInstallation\n============\n\n1. Install ``django-bootstrap-modal-forms``::\n\n    $ pip install django-bootstrap-modal-forms\n\n2. Add ``bootstrap_modal_forms`` to your INSTALLED_APPS in settings.py::\n\n    INSTALLED_APPS = [\n        ...\n        'bootstrap_modal_forms',\n        ...\n    ]\n\n3. Include Bootstrap, jQuery and ``jquery.bootstrap(5).modal.forms.js`` on 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 include ``jquery.bootstrap.modal.forms.js`` exactly as in code bellow.\n\n.. code-block:: html+django\n\n    \u003chead\u003e\n        \u003clink rel=\"stylesheet\" href=\"{% static 'assets/css/bootstrap.css' %}\"\u003e\n    \u003c/head\u003e\n\n    \u003cbody\u003e\n        \u003cscript src=\"{% static 'assets/js/bootstrap.js' %}\"\u003e\u003c/script\u003e\n\n        \u003c!-- Bootstrap 4 --\u003e\n        \u003cscript src=\"{% static 'assets/js/jquery-3.2.1.min.js' %}\"\u003e\u003c/script\u003e\n        \u003cscript src=\"{% static 'assets/js/popper.min.js' %}\"\u003e\u003c/script\u003e\n        \u003cscript src=\"{% static 'assets/js/bootstrap.min.js' %}\"\u003e\u003c/script\u003e\n        \u003c!-- You can alternatively load the minified version --\u003e\n        \u003cscript src=\"{% static 'js/jquery.bootstrap.modal.forms.js' %}\"\u003e\u003c/script\u003e\n\n        \u003c!-- Bootstrap 5 --\u003e\n        \u003cscript src=\"{% static 'assets/js/bootstrap.bundle.min.js' %}\"\u003e\u003c/script\u003e\n        \u003cscript src=\"{% static 'js/bootstrap5.modal.forms.js' %}\"\u003e\u003c/script\u003e\n        \u003c!-- You can alternatively load the minified version --\u003e\n        \u003cscript src=\"{% static 'js/bootstrap5.modal.forms.min.js' %}\"\u003e\u003c/script\u003e\n    \u003c/body\u003e\n\nHow it works?\n=============\n.. code-block:: html\n\n    index.html\n\n    \u003cscript type=\"text/javascript\"\u003e\n\n    // BS4\n    $(document).ready(function() {\n        $(\"#create-book\").modalForm({\n            formURL: \"{% url 'create_book' %}\"\n        });\n    });\n\n    // BS5\n    // instantiate single modal form\n    document.addEventListener('DOMContentLoaded', (e) =\u003e {\n      modalForm(document.getElementById('create-book'), {\n        formURL: \"{% url 'create_book' %}\"\n      })\n    });\n\n    // BS5\n    // instantiate multiple modal forms with unique formUrls\n    document.addEventListener('DOMContentLoaded', (e) =\u003e {\n      var deleteButtons = document.getElementsByClassName(\"delete-book\");\n      for (var index=0; index \u003c deleteButtons.length; index++) {\n        modalForm(deleteButtons[index], {\n          formURL: deleteButtons[index][\"dataset\"][\"formUrl\"],\n          isDeleteForm: true\n        });\n      }\n    });\n\n    \u003c/script\u003e\n\n1. Click event on html element instantiated with ``modalForm`` opens modal\n2. Form at ``formURL`` is appended to the modal\n3. On submit the form is POSTed via AJAX request to ``formURL``\n4. **Unsuccessful POST request** returns errors, which are shown in modal\n5. **Successful POST request** submits the form and redirects to ``success_url`` and shows ``success_message``, which are both defined in related Django view\n\nUsage\n=====\n\n1. Form\n*******\n\nDefine BookModelForm and inherit built-in form ``BSModalModelForm``.\n\n.. code-block:: python\n\n    forms.py\n\n    from .models import Book\n    from bootstrap_modal_forms.forms import BSModalModelForm\n\n    class BookModelForm(BSModalModelForm):\n        class Meta:\n            model = Book\n            fields = ['title', 'author', 'price']\n\n2. Form's html\n**************\n\nDefine form's html and save it as Django template.\n\n- Form will POST to ``formURL`` defined in #6.\n- Add ``class=\"invalid\"`` or custom ``errorClass`` (see paragraph **Options**) to the elements that wrap the fields\n- ``class=\"invalid\"`` acts as a flag for the fields having errors after the form has been POSTed.\n- **IMPORTANT NOTE:** Bootstrap 4 modal elements are used in this example. ``class=\"invalid\"`` is the default for Bootstrap 4. ``class=\"is-invalid\"`` is the default for Bootstrap 5.\n\n.. code-block:: html\n\n    book/create_book.html\n\n    \u003cform method=\"post\" action=\"\"\u003e\n      {% csrf_token %}\n\n     \u003cdiv class=\"modal-header\"\u003e\n        \u003ch5 class=\"modal-title\"\u003eCreate new Book\u003c/h5\u003e\n        \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n          \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-body\"\u003e\n        {% for field in form %}\n          \u003cdiv class=\"form-group{% if field.errors %} invalid{% endif %}\"\u003e\n            \u003clabel for=\"{{ field.id_for_label }}\"\u003e{{ field.label }}\u003c/label\u003e\n            {{ field }}\n            {% for error in field.errors %}\n              \u003cp class=\"help-block\"\u003e{{ error }}\u003c/p\u003e\n            {% endfor %}\n          \u003c/div\u003e\n        {% endfor %}\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-footer\"\u003e\n        \u003cbutton type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\"\u003eClose\u003c/button\u003e\n        \u003cbutton type=\"submit\" class=\"btn btn-primary\"\u003eCreate\u003c/button\u003e\n      \u003c/div\u003e\n\n    \u003c/form\u003e\n\n3. Function-based view\n**********************\nWhilst `django-boostrap-modal-forms` is primarily designed for class based usage (see below), there may be reasons you want\nto use its capabilities in classic function based views. To use them properly, you need to understand what exactly is going on\nand how you can adapt this mechanic into your own view.\n\nYour regular function based view might look like this\n\n.. code-block:: python\n\n    ...\n    if request.method == 'POST':\n        # do stuff\n    elif request.method == 'GET':\n        # do other stuff\n    else:\n        raise NotImplementedError('No stuff')\n    ...\n\nAs you continue to develop your logic, you may see, that two POST requests are being send on your forms, even tho, the user only submitted it once:\n- The **first** request can be used to verify your form's validity, let's call it the `ajax request` (you will see why).\n- The **second** request can be used to save your form's data (depending on whether the validation was successful or not)\n\nBut how do you differentiate between these two requests? Using this handy method: `is_ajax` (https://github.com/trco/django-bootstrap-modal-forms/blob/dddf22e78aead693fedcabe94961fb1ddebc6db7/bootstrap_modal_forms/utils.py#L1)\n\nSo, your code may now look like this and is capable of handling both POST requests:\n\n.. code-block:: python\n\n    ...\n    if request.method == \"POST\":\n        if form.is_valid():\n            if not is_ajax(request.META):\n                form.save()\n                messages.success(\n                    request,\n                    msg_success\n                )\n            return HttpResponseRedirect(redirect_url)\n    ...\n\n4. Class-based view\n*******************\n\nDefine a class-based view BookCreateView and inherit from built-in generic view ``BSModalCreateView``. BookCreateView processes the form defined in #1, uses the template defined in #2 and redirects to ``success_url`` showing ``success_message``.\n\n.. code-block:: python\n\n    views.py\n\n    from django.urls import reverse_lazy\n    from .forms import BookModelForm\n    from .models import Book\n    from bootstrap_modal_forms.generic import BSModalCreateView\n\n    class BookCreateView(BSModalCreateView):\n        template_name = 'examples/create_book.html'\n        form_class = BookModelForm\n        success_message = 'Success: Book was created.'\n        success_url = reverse_lazy('index')\n\n\n5. URL for the view\n*******************\n\nDefine URL for the view in #3.\n\n.. code-block:: python\n\n    from django.urls import path\n    from books import views\n\n    urlpatterns = [\n        path('', views.Index.as_view(), name='index'),\n        path('create/', views.BookCreateView.as_view(), name='create_book'),\n    ]\n\n6. Bootstrap modal and trigger element\n**************************************\n\nDefine the Bootstrap modal window and html element triggering modal opening.\n\n- **Single modal** can be used for multiple ``modalForms`` in single template (see #6).\n- When using **multiple modals** on the same page each modal should have unique ``id`` and the same value should also be set as ``modalID`` option when instantiating ``modalForm`` on trigger element.\n- Trigger element (in this example button with ``id=\"create-book\"``) is used for instantiation of ``modalForm`` in #6.\n- Any element can be trigger element as long as ``modalForm`` is bound to it.\n- Click event on trigger element loads form's html from #2 within ``\u003cdiv class=\"modal-content\"\u003e\u003c/div\u003e`` and sets action attribute of the form to ``formURL`` set in #6.\n\n.. code-block:: html+django\n\n    index.html\n\n    \u003cdiv class=\"modal fade\" tabindex=\"-1\" role=\"dialog\" id=\"modal\"\u003e\n      \u003cdiv class=\"modal-dialog\" role=\"document\"\u003e\n        \u003cdiv class=\"modal-content\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003c!-- Create book button --\u003e\n    \u003cbutton id=\"create-book\" class=\"btn btn-primary\" type=\"button\" name=\"button\"\u003eCreate book\u003c/button\u003e\n\n7. modalForm\n************\n\nAdd script to the template from #5 and bind the ``modalForm`` to the trigger element. Set BookCreateView URL defined in #4 as ``formURL`` property of ``modalForm``.\n\n- If you want to create **more modalForms in single template using the single modal window** from #5, repeat steps #1 to #4, create new trigger element as in #5 and bind the new ``modalForm`` with unique URL to it.\n- Default values for ``modalID``, ``modalContent``, ``modalForm`` and ``errorClass`` are used in this example, while ``formURL`` is customized. If you customize any other option adjust the code of the above examples accordingly.\n\n.. code-block:: html\n\n    index.html\n\n    \u003cscript type=\"text/javascript\"\u003e\n\n    // BS4\n    $(document).ready(function() {\n        $(\"#create-book\").modalForm({\n            formURL: \"{% url 'create_book' %}\"\n        });\n    });\n\n    // BS5\n    document.addEventListener('DOMContentLoaded', (e) =\u003e {\n      modalForm(document.getElementById('create-book'), {\n        formURL: \"{% url 'create_book' %}\"\n      })\n    });\n\n    \u003c/script\u003e\n\nAsync create/update with or without modal closing on submit\n===========================================================\n\nSet ``asyncUpdate`` and ``asyncSettings`` settings to create or update objects without page redirection to ``successUrl`` and define whether a modal should close or stay opened after form submission. See comments in example below and paragraph **modalForm options** for explanation of ``asyncSettings``.\nSee examples on how to properly reinstantiate modal forms for all CRUD buttons when using async options.\n\n.. code-block:: html\n\n    index.html\n\n    \u003c!-- asyncSettings.dataElementId --\u003e\n    \u003ctable id=\"books-table\" class=\"table\"\u003e\n      \u003cthead\u003e\n        ...\n      \u003c/thead\u003e\n      \u003ctbody\u003e\n      {% for book in books %}\n        \u003ctr\u003e\n            ...\n            \u003c!-- Update book buttons --\u003e\n            \u003cbutton type=\"button\" class=\"update-book btn btn-sm btn-primary\" data-form-url=\"{% url 'update_book' book.pk %}\"\u003e\n              \u003cspan class=\"fa fa-pencil\"\u003e\u003c/span\u003e\n            \u003c/button\u003e\n            ...\n          \u003c/td\u003e\n        \u003c/tr\u003e\n      {% endfor %}\n      \u003c/tbody\u003e\n    \u003c/table\u003e\n\n    \u003cscript type=\"text/javascript\"\u003e\n        $(function () {\n            ...\n\n            # asyncSettings.successMessage\n            var asyncSuccessMessage = [\n              \"\u003cdiv \",\n              \"style='position:fixed;top:0;z-index:10000;width:100%;border-radius:0;' \",\n              \"class='alert alert-icon alert-success alert-dismissible fade show mb-0' role='alert'\u003e\",\n              \"Success: Book was updated.\",\n              \"\u003cbutton type='button' class='close' data-dismiss='alert' aria-label='Close'\u003e\",\n              \"\u003cspan aria-hidden='true'\u003e\u0026times;\u003c/span\u003e\",\n              \"\u003c/button\u003e\",\n              \"\u003c/div\u003e\",\n              \"\u003cscript\u003e\",\n              \"$('.alert').fadeTo(2000, 500).slideUp(500, function () {$('.alert').slideUp(500).remove();});\",\n              \"\u003c\\/script\u003e\"\n            ].join();\n\n            # asyncSettings.addModalFormFunction\n            function updateBookModalForm() {\n              $(\".update-book\").each(function () {\n                $(this).modalForm({\n                  formURL: $(this).data(\"form-url\"),\n                  asyncUpdate: true,\n                  asyncSettings: {\n                    closeOnSubmit: false,\n                    successMessage: asyncSuccessMessage\n                    dataUrl: \"books/\",\n                    dataElementId: \"#books-table\",\n                    dataKey: \"table\",\n                    addModalFormFunction: updateBookModalForm\n                  }\n                });\n              });\n            }\n            updateBookModalForm();\n        \n            ...\n        });\n    \u003c/script\u003e\n\n.. code-block:: python\n\n    urls.py\n\n    from django.urls import path\n    from . import views\n\n    urlpatterns = [\n        ...\n        # asyncSettings.dataUrl\n        path('books/', views.books, name='books'),\n        ...\n    ]\n\n.. code-block:: python\n\n    views.py\n\n    from django.http import JsonResponse\n    from django.template.loader import render_to_string\n    from .models import Book\n\n    def books(request):\n        data = dict()\n        if request.method == 'GET':\n            books = Book.objects.all()\n            # asyncSettings.dataKey = 'table'\n            data['table'] = render_to_string( \n                '_books_table.html',\n                {'books': books},\n                request=request\n            )\n            return JsonResponse(data)\n\nmodalForm options\n=================\n\nmodalID\n  Sets the custom id of the modal. ``Default: \"#modal\"``\n\nmodalContent\n  Sets the custom class of the element to which the form's html is appended. If you change ``modalContent`` to the custom class, you should also change ``modalForm`` accordingly. To keep Bootstrap's modal style you should than copy Bootstrap's style for ``modal-content`` and set it to your new modalContent class. ``Default: \".modal-content\"``\n\nmodalForm\n  Sets the custom form selector. ``Default: \".modal-content form\"``\n\nformURL\n  Sets the url of the form's view and html. ``Default: null``\n\nisDeleteForm\n  Defines if form is used for deletion. Should be set to ``true`` for deletion forms.  ``Default: false``\n\nerrorClass\n  Sets the custom class for the form fields having errors. ``Default: \".invalid\" for Boostrap 4 and \".is-invalid\" for Bootstrap 5.``\n\nasyncUpdate\n  Sets asynchronous content update after form submission. ``Default: false``\n\nasyncSettings.closeOnSubmit\n  Sets whether modal closes or not after form submission. ``Default: false``\n\nasyncSettings.successMessage\n  Sets successMessage shown after succesful for submission. Should be set to string defining message element. See ``asyncSuccessMessage`` example above. ``Default: null``\n\nasyncSettings.dataUrl\n  Sets url of the view returning new queryset = all of the objects plus newly created or updated one after asynchronous update. ``Default: null``\n\nasyncSettings.dataElementId\n  Sets the ``id`` of the element which rerenders asynchronously updated queryset. ``Default: null``\n\nasyncSettings.dataKey\n  Sets the key containing asynchronously updated queryset in the data dictionary returned from the view providing updated queryset. ``Default: null``\n\nasyncSettings.addModalFormFunction\n  Sets the method needed for reinstantiation of event listeners on buttons (single or all CRUD buttons) after asynchronous update. ``Default: null``\n\nmodalForm default settings object and it's structure\n****************************************************\n\n.. code-block:: html\n  \n    triggerElement.modalForm({\n        modalID: \"#modal\",\n        modalContent: \".modal-content\",\n        modalForm: \".modal-content form\",\n        formURL: null,\n        isDeleteForm: false,\n        // \".invalid\" is the default for Bootstrap 4. \".is-invalid\" is the default for Bootstrap 5.\n        errorClass: \".invalid\",\n        asyncUpdate: false,\n        asyncSettings: {\n            closeOnSubmit: false,\n            successMessage: null,\n            dataUrl: null,\n            dataElementId: null,\n            dataKey: null,\n            addModalFormFunction: null\n        }\n    });\n\nForms\n=====\n\nImport forms with ``from bootstrap_modal_forms.forms import BSModalForm``.\n\nBSModalForm\n    Inherits PopRequestMixin and Django's forms.Form.\n\nBSModalModelForm\n    Inherits PopRequestMixin, CreateUpdateAjaxMixin and Django's forms.ModelForm.\n\nMixins\n======\n\nImport mixins with ``from bootstrap_modal_forms.mixins import PassRequestMixin``.\n\nPassRequestMixin\n    Form Mixin which puts the request into the form's kwargs. Note: Using this mixin requires you to pop the `request` kwarg out of the dict in the super of your form's `__init__`. See PopRequestMixin.\n\nPopRequestMixin\n    Form 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.\n\nCreateUpdateAjaxMixin\n    ModelForm Mixin which passes or saves object based on request type.\n\nDeleteMessageMixin\n    Generic 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.\n\nFormValidationMixin\n    Generic View Mixin which saves object and redirects to success_url if request is not ajax request. Otherwise response 204 No content is returned.\n\nLoginAjaxMixin\n    Generic View Mixin which authenticates user if request is not ajax request.\n\nGeneric views\n=============\n\nImport generic views with ``from bootstrap_modal_forms.generic import BSModalFormView``.\n\nBSModalLoginView\n    Inhertis LoginAjaxMixin and Django's LoginView.\n\nBSModalFormView\n    Inherits PassRequestMixin and Django's generic.FormView.\n\nBSModalCreateView\n    Inherits PassRequestMixin, FormValidationMixin and generic.CreateView.\n\nBSModalUpdateView\n    Inherits PassRequestMixin, FormValidationMixin and generic.UpdateView.\n\nBSModalReadView\n    Inherits Django's generic.DetailView.\n\nBSModalDeleteView\n    Inherits DeleteMessageMixin and Django's generic.DeleteView.\n\nExamples\n========\n\nTo see ``django-bootstrap-modal-forms`` in action clone the repository and run the examples locally::\n\n    $ git clone https://github.com/trco/django-bootstrap-modal-forms.git\n    $ cd django-bootstrap-modal-forms\n    $ pip install -r requirements.txt\n    $ python manage.py migrate\n    $ python manage.py runserver\n\nExample 1: Signup form in Bootstrap modal\n*****************************************\n\nFor explanation how all the parts of the code work together see paragraph **Usage**. To test the working solution presented here clone and run **Examples**.\n\n.. code-block:: python\n\n    forms.py\n\n    from django.contrib.auth.forms import UserCreationForm\n    from django.contrib.auth.models import User\n    from bootstrap_modal_forms.mixins import PopRequestMixin, CreateUpdateAjaxMixin\n\n\n    class CustomUserCreationForm(PopRequestMixin, CreateUpdateAjaxMixin,\n                                 UserCreationForm):\n        class Meta:\n            model = User\n            fields = ['username', 'password1', 'password2']\n\n.. code-block:: html\n\n    signup.html\n\n    {% load widget_tweaks %}\n\n    \u003cform method=\"post\" action=\"\"\u003e\n      {% csrf_token %}\n\n      \u003cdiv class=\"modal-header\"\u003e\n        \u003ch3 class=\"modal-title\"\u003eSign up\u003c/h3\u003e\n        \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n          \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-body\"\u003e\n\n        \u003cdiv class=\"{% if form.non_field_errors %}invalid{% endif %} mb-2\"\u003e\n          {% for error in form.non_field_errors %}\n            {{ error }}\n          {% endfor %}\n        \u003c/div\u003e\n\n        {% for field in form %}\n          \u003cdiv class=\"form-group\"\u003e\n            \u003clabel for=\"{{ field.id_for_label }}\"\u003e{{ field.label }}\u003c/label\u003e\n            {% render_field field class=\"form-control\" placeholder=field.label %}\n            \u003cdiv class=\"{% if field.errors %} invalid{% endif %}\"\u003e\n              {% for error in field.errors %}\n                \u003cp class=\"help-block\"\u003e{{ error }}\u003c/p\u003e\n              {% endfor %}\n            \u003c/div\u003e\n          \u003c/div\u003e\n        {% endfor %}\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-footer\"\u003e\n        \u003cbutton type=\"submit\" class=\"btn btn-primary\"\u003eSign up\u003c/button\u003e\n      \u003c/div\u003e\n\n    \u003c/form\u003e\n\n.. code-block:: python\n\n    views.py\n\n    from django.urls import reverse_lazy\n    from bootstrap_modal_forms.generic import BSModalCreateView\n    from .forms import CustomUserCreationForm\n\n    class SignUpView(BSModalCreateView):\n        form_class = CustomUserCreationForm\n        template_name = 'examples/signup.html'\n        success_message = 'Success: Sign up succeeded. You can now Log in.'\n        success_url = reverse_lazy('index')\n\n.. code-block:: python\n\n    urls.py\n\n    from django.urls import path\n    from . import views\n\n    app_name = 'accounts'\n    urlpatterns = [\n        path('signup/', views.SignUpView.as_view(), name='signup')\n    ]\n\n\n.. code-block:: html\n\n    .html file containing modal, trigger element and script instantiating modalForm\n\n    \u003cdiv class=\"modal fade\" tabindex=\"-1\" role=\"dialog\" id=\"modal\"\u003e\n      \u003cdiv class=\"modal-dialog\" role=\"document\"\u003e\n        \u003cdiv class=\"modal-content\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003cbutton id=\"signup-btn\" class=\"btn btn-primary\" type=\"button\" name=\"button\"\u003eSign up\u003c/button\u003e\n\n    \u003cscript type=\"text/javascript\"\u003e\n      $(function () {\n        // Sign up button\n        $(\"#signup-btn\").modalForm({\n            formURL: \"{% url 'signup' %}\"\n        });\n      });\n    \u003c/script\u003e\n\nExample 2: Login form in Bootstrap modal\n****************************************\n\nFor explanation how all the parts of the code work together see paragraph **Usage**. To test the working solution presented here clone and run **Examples**.\n\nYou can set the login redirection by setting the ``LOGIN_REDIRECT_URL`` in ``settings.py``.\n\nYou can also set the custom login redirection by:\n\n1. Adding ``success_url`` to the ``extra_context`` of ``CustomLoginView``\n2. Setting this ``success_url`` variable as a value of the ``hidden input field`` with ``name=\"next\"`` within the Login form html\n\n.. code-block:: python\n\n    forms.py\n\n    from django.contrib.auth.forms import AuthenticationForm\n    from django.contrib.auth.models import User\n\n    class CustomAuthenticationForm(AuthenticationForm):\n        class Meta:\n            model = User\n            fields = ['username', 'password']\n\n.. code-block:: html\n\n    login.html\n\n    {% load widget_tweaks %}\n\n    \u003cform method=\"post\" action=\"\"\u003e\n      {% csrf_token %}\n\n      \u003cdiv class=\"modal-header\"\u003e\n        \u003ch3 class=\"modal-title\"\u003eLog in\u003c/h3\u003e\n        \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n          \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-body\"\u003e\n\n        \u003cdiv class=\"{% if form.non_field_errors %}invalid{% endif %} mb-2\"\u003e\n          {% for error in form.non_field_errors %}\n            {{ error }}\n          {% endfor %}\n        \u003c/div\u003e\n\n        {% for field in form %}\n          \u003cdiv class=\"form-group\"\u003e\n            \u003clabel for=\"{{ field.id_for_label }}\"\u003e{{ field.label }}\u003c/label\u003e\n            {% render_field field class=\"form-control\" placeholder=field.label %}\n            \u003cdiv class=\"{% if field.errors %} invalid{% endif %}\"\u003e\n              {% for error in field.errors %}\n                \u003cp class=\"help-block\"\u003e{{ error }}\u003c/p\u003e\n              {% endfor %}\n            \u003c/div\u003e\n          \u003c/div\u003e\n        {% endfor %}\n\n        \u003c!-- Hidden input field for custom redirection after successful login --\u003e\n        \u003cinput type=\"hidden\" name=\"next\" value=\"{{ success_url }}\"\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-footer\"\u003e\n        \u003cbutton type=\"submit\" class=\"btn btn-primary\"\u003eLog in\u003c/button\u003e\n      \u003c/div\u003e\n\n    \u003c/form\u003e\n\n.. code-block:: python\n\n    views.py\n\n    from django.urls import reverse_lazy\n    from bootstrap_modal_forms.generic import BSModalLoginView\n    from .forms import CustomAuthenticationForm\n\n    class CustomLoginView(BSModalLoginView):\n        authentication_form = CustomAuthenticationForm\n        template_name = 'examples/login.html'\n        success_message = 'Success: You were successfully logged in.'\n        extra_context = dict(success_url=reverse_lazy('index'))\n\n.. code-block:: python\n\n    urls.py\n\n    from django.urls import path\n    from . import views\n\n    app_name = 'accounts'\n    urlpatterns = [\n        path('login/', views.CustomLoginView.as_view(), name='login')\n    ]\n\n.. code-block:: html\n\n    .html file containing modal, trigger element and script instantiating modalForm\n\n    \u003cdiv class=\"modal fade\" tabindex=\"-1\" role=\"dialog\" id=\"modal\"\u003e\n      \u003cdiv class=\"modal-dialog\" role=\"document\"\u003e\n        \u003cdiv class=\"modal-content\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003cbutton id=\"login-btn\" class=\"btn btn-primary\" type=\"button\" name=\"button\"\u003eSign up\u003c/button\u003e\n\n    \u003cscript type=\"text/javascript\"\u003e\n      $(function () {\n        // Log in button\n        $(\"#login-btn\").modalForm({\n            formURL: \"{% url 'login' %}\"\n        });\n      });\n    \u003c/script\u003e\n\nExample 3: Django's forms.ModelForm (CRUD forms) in Bootstrap modal\n*******************************************************************\n\nFor explanation how all the parts of the code work together see paragraph **Usage**. To test the working solution presented here clone and run **Examples**.\n\n.. code-block:: python\n\n    forms.py\n\n    from .models import Book\n    from bootstrap_modal_forms.forms import BSModalModelForm\n\n\n    class BookModelForm(BSModalModelForm):\n        class Meta:\n            model = Book\n            exclude = ['timestamp']\n\n.. code-block:: html\n\n    create_book.html\n\n    {% load widget_tweaks %}\n\n    \u003cform method=\"post\" action=\"\"\u003e\n      {% csrf_token %}\n\n      \u003cdiv class=\"modal-header\"\u003e\n        \u003ch3 class=\"modal-title\"\u003eCreate Book\u003c/h3\u003e\n        \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n          \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-body\"\u003e\n\n        \u003cdiv class=\"{% if form.non_field_errors %}invalid{% endif %} mb-2\"\u003e\n          {% for error in form.non_field_errors %}\n            {{ error }}\n          {% endfor %}\n        \u003c/div\u003e\n\n        {% for field in form %}\n          \u003cdiv class=\"form-group\"\u003e\n            \u003clabel for=\"{{ field.id_for_label }}\"\u003e{{ field.label }}\u003c/label\u003e\n            {% render_field field class=\"form-control\" placeholder=field.label %}\n            \u003cdiv class=\"{% if field.errors %} invalid{% endif %}\"\u003e\n              {% for error in field.errors %}\n                \u003cp class=\"help-block\"\u003e{{ error }}\u003c/p\u003e\n              {% endfor %}\n            \u003c/div\u003e\n          \u003c/div\u003e\n        {% endfor %}\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-footer\"\u003e\n        \u003cbutton type=\"submit\" class=\"btn btn-primary\"\u003eCreate\u003c/button\u003e\n      \u003c/div\u003e\n\n    \u003c/form\u003e\n\n.. code-block:: html\n\n    update_book.html\n\n    {% load widget_tweaks %}\n\n    \u003cform method=\"post\" action=\"\"\u003e\n      {% csrf_token %}\n\n      \u003cdiv class=\"modal-header\"\u003e\n        \u003ch3 class=\"modal-title\"\u003eUpdate Book\u003c/h3\u003e\n        \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n          \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-body\"\u003e\n        \u003cdiv class=\"{% if form.non_field_errors %}invalid{% endif %} mb-2\"\u003e\n          {% for error in form.non_field_errors %}\n            {{ error }}\n          {% endfor %}\n        \u003c/div\u003e\n\n        {% for field in form %}\n          \u003cdiv class=\"form-group\"\u003e\n            \u003clabel for=\"{{ field.id_for_label }}\"\u003e{{ field.label }}\u003c/label\u003e\n            {% render_field field class=\"form-control\" placeholder=field.label %}\n            \u003cdiv class=\"{% if field.errors %} invalid{% endif %}\"\u003e\n              {% for error in field.errors %}\n                \u003cp class=\"help-block\"\u003e{{ error }}\u003c/p\u003e\n              {% endfor %}\n            \u003c/div\u003e\n          \u003c/div\u003e\n        {% endfor %}\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-footer\"\u003e\n        \u003cbutton type=\"submit\" class=\"btn btn-primary\"\u003eUpdate\u003c/button\u003e\n      \u003c/div\u003e\n\n    \u003c/form\u003e\n\n.. code-block:: html\n\n    read_book.html\n\n    {% load widget_tweaks %}\n\n    \u003cdiv class=\"modal-header\"\u003e\n      \u003ch3 class=\"modal-title\"\u003eBook details\u003c/h3\u003e\n      \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n        \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n      \u003c/button\u003e\n    \u003c/div\u003e\n\n    \u003cdiv class=\"modal-body\"\u003e\n      \u003cdiv class=\"\"\u003e\n        Title: {{ book.title }}\n      \u003c/div\u003e\n      \u003cdiv class=\"\"\u003e\n        Author: {{ book.author }}\n      \u003c/div\u003e\n      \u003cdiv class=\"\"\u003e\n        Price: {{ book.price }} €\n      \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003cdiv class=\"modal-footer\"\u003e\n      \u003cbutton type=\"button\" class=\"btn btn-default\" data-dismiss=\"modal\"\u003eClose\u003c/button\u003e\n    \u003c/div\u003e\n\n.. code-block:: html\n\n    {% load widget_tweaks %}\n\n    \u003cform method=\"post\" action=\"\"\u003e\n      {% csrf_token %}\n\n      \u003cdiv class=\"modal-header\"\u003e\n        \u003ch3 class=\"modal-title\"\u003eDelete Book\u003c/h3\u003e\n        \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n          \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-body\"\u003e\n        \u003cp\u003eAre you sure you want to delete book with title\n          \u003cstrong\u003e{{ book.title }}\u003c/strong\u003e?\u003c/p\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-footer\"\u003e\n        \u003cbutton type=\"submit\" class=\"btn btn-danger\"\u003eDelete\u003c/button\u003e\n      \u003c/div\u003e\n\n    \u003c/form\u003e\n\n.. code-block:: python\n\n    views.py\n\n    from django.urls import reverse_lazy\n    from django.views import generic\n    from .forms import BookModelForm\n    from .models import Book\n    from bootstrap_modal_forms.generic import (\n      BSModalCreateView,\n      BSModalUpdateView,\n      BSModalReadView,\n      BSModalDeleteView\n    )\n\n    class Index(generic.ListView):\n        model = Book\n        context_object_name = 'books'\n        template_name = 'index.html'\n\n    # Create\n    class BookCreateView(BSModalCreateView):\n        template_name = 'examples/create_book.html'\n        form_class = BookModelForm\n        success_message = 'Success: Book was created.'\n        success_url = reverse_lazy('index')\n\n    # Update\n    class BookUpdateView(BSModalUpdateView):\n        model = Book\n        template_name = 'examples/update_book.html'\n        form_class = BookModelForm\n        success_message = 'Success: Book was updated.'\n        success_url = reverse_lazy('index')\n\n    # Read\n    class BookReadView(BSModalReadView):\n        model = Book\n        template_name = 'examples/read_book.html'\n\n    # Delete\n    class BookDeleteView(BSModalDeleteView):\n        model = Book\n        template_name = 'examples/delete_book.html'\n        success_message = 'Success: Book was deleted.'\n        success_url = reverse_lazy('index')\n\n.. code-block:: python\n\n    urls.py\n\n    from django.urls import path\n    from books import views\n\n    urlpatterns = [\n        path('', views.Index.as_view(), name='index'),\n        path('create/', views.BookCreateView.as_view(), name='create_book'),\n        path('update/\u003cint:pk\u003e', views.BookUpdateView.as_view(), name='update_book'),\n        path('read/\u003cint:pk\u003e', views.BookReadView.as_view(), name='read_book'),\n        path('delete/\u003cint:pk\u003e', views.BookDeleteView.as_view(), name='delete_book')\n    ]\n\n.. code-block:: html\n\n    .html file containing modal, trigger elements and script instantiating modalForms\n\n    \u003c!-- Modal 1 with id=\"create-book\"--\u003e\n    \u003cdiv class=\"modal fade\" id=\"create-modal\" tabindex=\"-1\" role=\"dialog\" aria-hidden=\"true\"\u003e\n      \u003cdiv class=\"modal-dialog\"\u003e\n        \u003cdiv class=\"modal-content\"\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003c!-- Modal 2 with id=\"modal\" --\u003e\n    \u003cdiv class=\"modal fade\" tabindex=\"-1\" role=\"dialog\" id=\"modal\"\u003e\n      \u003cdiv class=\"modal-dialog\" role=\"document\"\u003e\n        \u003cdiv class=\"modal-content\"\u003e\u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/div\u003e\n\n    \u003c!-- Create book button --\u003e\n    \u003cbutton id=\"create-book\" class=\"btn btn-primary\" type=\"button\" name=\"button\"\u003eCreate book\u003c/button\u003e\n\n    {% for book in books %}\n        \u003cdiv class=\"text-center\"\u003e\n          \u003c!-- Read book buttons --\u003e\n          \u003cbutton type=\"button\" class=\"read-book bs-modal btn btn-sm btn-primary\" data-form-url=\"{% url 'read_book' book.pk %}\"\u003e\n            \u003cspan class=\"fa fa-eye\"\u003e\u003c/span\u003e\n          \u003c/button\u003e\n          \u003c!-- Update book buttons --\u003e\n          \u003cbutton type=\"button\" class=\"update-book bs-modal btn btn-sm btn-primary\" data-form-url=\"{% url 'update_book' book.pk %}\"\u003e\n            \u003cspan class=\"fa fa-pencil\"\u003e\u003c/span\u003e\n          \u003c/button\u003e\n          \u003c!-- Delete book buttons --\u003e\n          \u003cbutton type=\"button\" class=\"delete-book bs-modal btn btn-sm btn-danger\" data-form-url=\"{% url 'delete_book' book.pk %}\"\u003e\n            \u003cspan class=\"fa fa-trash\"\u003e\u003c/span\u003e\n          \u003c/button\u003e\n        \u003c/div\u003e\n    {% endfor %}\n\n    \u003cscript type=\"text/javascript\"\u003e\n      $(function () {\n\n        // Read book buttons\n        $(\".read-book\").each(function () {\n            $(this).modalForm({formURL: $(this).data(\"form-url\")});\n        });\n\n        // Delete book buttons - formURL is retrieved from the data of the element\n        $(\".delete-book\").each(function () {\n            $(this).modalForm({formURL: $(this).data(\"form-url\"), isDeleteForm: true});\n        });\n\n        // Create book button opens form in modal with id=\"create-modal\"\n        $(\"#create-book\").modalForm({\n            formURL: \"{% url 'create_book' %}\",\n            modalID: \"#create-modal\"\n        });\n\n      });\n    \u003c/script\u003e\n\n- See the difference between button triggering Create action and buttons triggering Read, Update and Delete actions.\n- Within the for loop in .html file the ``data-form-url`` attribute 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.\n- These ``data-form-url`` URLs should than be set as ``formURLs`` for ``modalForms`` bound to the buttons.\n\nExample 4: Django's forms.Form in Bootstrap modal\n*************************************************\n\nFor explanation how all the parts of the code work together see paragraph **Usage**. To test the working solution presented here clone and run **Examples**.\n\n.. code-block:: python\n\n    forms.py\n\n    from bootstrap_modal_forms.forms import BSModalForm\n\n    class BookFilterForm(BSModalForm):\n        type = forms.ChoiceField(choices=Book.BOOK_TYPES)\n\n        class Meta:\n            fields = ['type']\n\n.. code-block:: html\n\n    filter_book.html\n\n    {% load widget_tweaks %}\n\n    \u003cform method=\"post\" action=\"\"\u003e\n      {% csrf_token %}\n\n      \u003cdiv class=\"modal-header\"\u003e\n        \u003ch3 class=\"modal-title\"\u003eFilter Books\u003c/h3\u003e\n        \u003cbutton type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\"\u003e\n          \u003cspan aria-hidden=\"true\"\u003e\u0026times;\u003c/span\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-body\"\u003e\n        \u003cdiv class=\"{% if form.non_field_errors %}invalid{% endif %} mb-2\"\u003e\n          {% for error in form.non_field_errors %}\n            {{ error }}\n          {% endfor %}\n        \u003c/div\u003e\n\n        {% for field in form %}\n          \u003cdiv class=\"form-group\"\u003e\n            \u003clabel for=\"{{ field.id_for_label }}\"\u003e{{ field.label }}\u003c/label\u003e\n            {% render_field field class=\"form-control\" placeholder=field.label %}\n            \u003cdiv class=\"{% if field.errors %} invalid{% endif %}\"\u003e\n              {% for error in field.errors %}\n                \u003cp class=\"help-block\"\u003e{{ error }}\u003c/p\u003e\n              {% endfor %}\n            \u003c/div\u003e\n          \u003c/div\u003e\n        {% endfor %}\n      \u003c/div\u003e\n\n      \u003cdiv class=\"modal-footer\"\u003e\n        \u003cbutton type=\"submit\" class=\"btn btn-primary\"\u003eFilter\u003c/button\u003e\n      \u003c/div\u003e\n\n    \u003c/form\u003e\n\n.. code-block:: python\n\n    views.py\n\n    class BookFilterView(BSModalFormView):\n        template_name = 'examples/filter_book.html'\n        form_class = BookFilterForm\n\n        def form_valid(self, form):\n            self.filter = '?type=' + form.cleaned_data['type']\n            response = super().form_valid(form)\n            return response\n\n        def get_success_url(self):\n            return reverse_lazy('index') + self.filter\n\n.. code-block:: python\n\n    urls.py\n\n    from django.urls import path\n    from . import views\n\n    app_name = 'accounts'\n    urlpatterns = [\n        path('filter/', views.BookFilterView.as_view(), name='filter_book'),\n    ]\n\n.. code-block:: html\n\n    index.html\n      \n      ...\n      \u003cbutton id=\"filter-book\" class=\"filter-book btn btn-primary\" type=\"button\" name=\"button\" data-form-url=\"{% url 'filter_book' %}\"\u003e\n        \u003cspan class=\"fa fa-filter mr-2\"\u003e\u003c/span\u003eFilter books\n      \u003c/button\u003e\n      ...\n\n      \u003cscript type=\"text/javascript\"\u003e\n        $(function () {\n          ...\n          $(\"#filter-book\").each(function () {\n              $(this).modalForm({formURL: $(this).data('form-url')});\n          });\n          ...\n        });\n      \u003c/script\u003e\n\nLicense\n=======\n\nThis project is licensed under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrco%2Fdjango-bootstrap-modal-forms","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrco%2Fdjango-bootstrap-modal-forms","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrco%2Fdjango-bootstrap-modal-forms/lists"}