diff --git a/CHANGELOG.rst b/CHANGELOG.rst deleted file mode 100644 index da0590c..0000000 --- a/CHANGELOG.rst +++ /dev/null @@ -1,140 +0,0 @@ -========= -Changelog -========= - -3.0.4 (2023-06-18) -================== - -- fix broken examples by bumping django-widget-tweaks dependency version - -3.0.3 (2023-06-04) -================== - -- add get_success_message method in FormValidationMixin - - -3.0.2 (2023-05-02) -================== - -- fix call to get_success_url method in FormValidationMixin - -3.0.1 (2023-05-02) -================== - -- fix redirect in FormValidationMixin - -3.0.0 (2023-05-02) -================== - -- deprecate support for python < 3.8 -- deprecate support for Django < 3.2 -- deprecate SuccessMessageMixin -- add FormValidationMixin -- add support for Chrome, Firefox, Edge and Safari drivers when running funtional tests -- update examples to Django=4.2 -- update README.rst - -2.2.1 (2023-03-05) -================== - -- add support for Bootstrap5 without jQuery dependency -- update documentation with Bootstrap5 examples - -2.2.0 (2021-04-27) -================== - -- add custom is_ajax function since Django's is_ajax is deprectated -- change post method to delete method in DeleteMessageMixin - -2.1.0 (2021-03-06) -================== - -- fix form submission with button type submit - -2.0.1 (2020-11-22) -================== - -- fix file uploads by updating form serialization - -2.0.0 (2020-06-28) -================== - -- rename BSModalForm to BSModalModelForm supporting Django's forms.ModelForm -- add support for Django's forms.Form with BSModalForm -- add generic view BSModalFormView -- add support for asynchronous page updating after form submission - -1.5.0 (2019-11-23) -================== - -- disable submitBtn after submission -- add support for multiple modals with unique ids on single page - -1.4.4 (2019-09-29) -================== - -- add support for Django development versions - -1.4.3 (2019-09-15) -================== - -- add support for Django>=1.8 - -1.4.2 (2019-04-15) -================== - -- change sync to async when validating form and fix warning: [Deprecation] Synchronous XMLHttpRequest on the main thread - -1.4.1 (2019-04-02) -================== - -- add functional tests - -1.4.0 (2019-03-31) -================== - -- add unit tests -- change DeleteAjaxMixin to DeleteMessageMixin - -1.3.2 (2019-03-30) -================== - -- add generic views BSModalCreateView, BSModalUpdateView, BSModalReadView, BSModalDeleteView, BSModalLoginView -- add form BSModalForm -- update README.rst - -1.3.1 (2018-08-31) -================== - -- fix deleted release 1.3.0 at pypi - -1.3.0 (2018-08-31) -================== - -- support Django messages framework -- fix redirection to success_url -- update README.rst - -1.2.1 (2018-08-14) -================== - -- fix formURL setup after invalid form submission returns errors via Ajax -- update README.rst - -1.2.0 (2018-08-12) -================== - -- update formURL setup to support a dynamic setup of form's action attribute -- support Django UpdateView -- update README.rst - -1.1.0 (2018-08-11) -================== - -- fix redirection to success_url -- update README.rst - -1.0 (2018-05-28) -================ - -Initial release. diff --git a/README.rst b/README.rst index d6ad772..73cb0db 100644 --- a/README.rst +++ b/README.rst @@ -9,13 +9,19 @@ A Django plugin for creating AJAX driven forms in Bootstrap modal. :local: :backlinks: none -Live Demo -========= +Test and experiment on your machine +=================================== -Demo_ +This 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. -.. _Demo: http://trco.silkym.com/dbmf/ +Note 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. +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:8000 General information =================== @@ -28,17 +34,6 @@ Contribute ********** This is an Open Source project and any contribution is highly appreciated. - -Test and experiment on your machine -=================================== - -This 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. 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:8000 - Tests ===== @@ -154,10 +149,10 @@ Define BookModelForm and inherit built-in form ``BSModalModelForm``. Define form's html and save it as Django template. -- Bootstrap 4 modal elements are used in this example. - Form will POST to ``formURL`` defined in #6. -- Add ``class="invalid"`` or custom ``errorClass`` (see paragraph **Options**) to the elements that wrap the fields. +- Add ``class="invalid"`` or custom ``errorClass`` (see paragraph **Options**) to the elements that wrap the fields - ``class="invalid"`` acts as a flag for the fields having errors after the form has been POSTed. +- **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. .. code-block:: html @@ -192,7 +187,48 @@ Define form's html and save it as Django template. -3. Class-based view +3. Function-based view +********************** +Whilst `django-boostrap-modal-forms` is primarily designed for class based usage (see below), there may be reasons you want +to use its capabilities in classic function based views. To use them properly, you need to understand what exactly is going on +and how you can adapt this mechanic into your own view. + +Your regular function based view might look like this + +.. code-block:: python + + ... + if request.method == 'POST': + # do stuff + elif request.method == 'GET': + # do other stuff + else: + raise NotImplementedError('No stuff') + ... + +As 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: +- The **first** request can be used to verify your form's validity, let's call it the `ajax request` (you will see why). +- The **second** request can be used to save your form's data (depending on whether the validation was successful or not) + +But 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) + +So, your code may now look like this and is capable of handling both POST requests: + +.. code-block:: python + + ... + if request.method == "POST": + if form.is_valid(): + if not is_ajax(request.META): + form.save() + messages.success( + request, + msg_success + ) + return HttpResponseRedirect(redirect_url) + ... + +4. Class-based view ******************* Define 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``. @@ -212,7 +248,8 @@ Define a class-based view BookCreateView and inherit from built-in generic view success_message = 'Success: Book was created.' success_url = reverse_lazy('index') -4. URL for the view + +5. URL for the view ******************* Define URL for the view in #3. @@ -227,7 +264,7 @@ Define URL for the view in #3. path('create/', views.BookCreateView.as_view(), name='create_book'), ] -5. Bootstrap modal and trigger element +6. Bootstrap modal and trigger element ************************************** Define the Bootstrap modal window and html element triggering modal opening. @@ -251,7 +288,7 @@ Define the Bootstrap modal window and html element triggering modal opening. -6. modalForm +7. modalForm ************ Add 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``. @@ -406,7 +443,7 @@ isDeleteForm Defines if form is used for deletion. Should be set to ``true`` for deletion forms. ``Default: false`` errorClass - Sets the custom class for the form fields having errors. ``Default: ".invalid"`` + Sets the custom class for the form fields having errors. ``Default: ".invalid" for Boostrap 4 and ".is-invalid" for Bootstrap 5.`` asyncUpdate Sets asynchronous content update after form submission. ``Default: false`` @@ -440,6 +477,7 @@ modalForm default settings object and it's structure modalForm: ".modal-content form", formURL: null, isDeleteForm: false, + // ".invalid" is the default for Bootstrap 4. ".is-invalid" is the default for Bootstrap 5. errorClass: ".invalid", asyncUpdate: false, asyncSettings: { diff --git a/bootstrap_modal_forms/mixins.py b/bootstrap_modal_forms/mixins.py index eeaff5d..c419f84 100644 --- a/bootstrap_modal_forms/mixins.py +++ b/bootstrap_modal_forms/mixins.py @@ -93,10 +93,10 @@ def form_valid(self, form): if isAjaxRequest: if asyncUpdate: - form.save() + self.object = form.save() return HttpResponse(status=204) - form.save() + self.object = form.save() messages.success(self.request, self.get_success_message()) return HttpResponseRedirect(self.get_success_url()) diff --git a/bootstrap_modal_forms/static/js/bootstrap5.modal.forms.js b/bootstrap_modal_forms/static/js/bootstrap5.modal.forms.js index 2aaa5fe..4ea3f07 100644 --- a/bootstrap_modal_forms/static/js/bootstrap5.modal.forms.js +++ b/bootstrap_modal_forms/static/js/bootstrap5.modal.forms.js @@ -1,6 +1,6 @@ /* django-bootstrap-modal-forms -version : 3.0.4 +version : 3.0.5 Copyright (c) 2023 Marcel Rupp */ diff --git a/bootstrap_modal_forms/static/js/jquery.bootstrap.modal.forms.js b/bootstrap_modal_forms/static/js/jquery.bootstrap.modal.forms.js index dca793a..5fd185e 100644 --- a/bootstrap_modal_forms/static/js/jquery.bootstrap.modal.forms.js +++ b/bootstrap_modal_forms/static/js/jquery.bootstrap.modal.forms.js @@ -1,6 +1,6 @@ /* django-bootstrap-modal-forms -version : 3.0.4 +version : 3.0.5 Copyright (c) 2023 Uroš Trstenjak https://github.com/trco/django-bootstrap-modal-forms */ diff --git a/requirements.txt b/requirements.txt index a4b23f9..f75c5f7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ # End of life Django 4.2: April 2026 # @see https://www.djangoproject.com/download/#supported-versions -Django==4.2.1 +Django==4.2.7 django-widget-tweaks==1.4.12 selenium==3.14 diff --git a/setup.py b/setup.py index c544415..4fffc80 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,7 @@ setup( name='django-bootstrap-modal-forms', - version='3.0.4', + version='3.0.5', packages=find_packages(), include_package_data=True, license='MIT License',