Giter Club home page Giter Club logo

django-bootstrap-modal-forms's Introduction

Django Bootstrap Modal Forms

A Django plugin for creating AJAX driven forms in Bootstrap modal.

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.

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

Opening an issue

When 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.

Contribute

This is an Open Source project and any contribution is highly appreciated.

Tests

Run unit and functional tests inside of project folder:

$ python manage.py test

Installation

  1. Install django-bootstrap-modal-forms:

    $ pip install django-bootstrap-modal-forms
    
  2. Add bootstrap_modal_forms to your INSTALLED_APPS in settings.py:

    INSTALLED_APPS = [
        ...
        'bootstrap_modal_forms',
        ...
    ]
    
  3. 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.

<head>
    <link rel="stylesheet" href="{% static 'assets/css/bootstrap.css' %}">
</head>

<body>
    <script src="{% static 'assets/js/bootstrap.js' %}"></script>

    <!-- Bootstrap 4 -->
    <script src="{% static 'assets/js/jquery-3.2.1.min.js' %}"></script>
    <script src="{% static 'assets/js/popper.min.js' %}"></script>
    <script src="{% static 'assets/js/bootstrap.min.js' %}"></script>
    <!-- You can alternatively load the minified version -->
    <script src="{% static 'js/jquery.bootstrap.modal.forms.js' %}"></script>

    <!-- Bootstrap 5 -->
    <script src="{% static 'assets/js/bootstrap.bundle.min.js' %}"></script>
    <script src="{% static 'js/bootstrap5.modal.forms.js' %}"></script>
    <!-- You can alternatively load the minified version -->
    <script src="{% static 'js/bootstrap5.modal.forms.min.js' %}"></script>
</body>

How it works?

index.html

<script type="text/javascript">

// BS4
$(document).ready(function() {
    $("#create-book").modalForm({
        formURL: "{% url 'create_book' %}"
    });
});

// BS5
// instantiate single modal form
document.addEventListener('DOMContentLoaded', (e) => {
  modalForm(document.getElementById('create-book'), {
    formURL: "{% url 'create_book' %}"
  })
});

// BS5
// instantiate multiple modal forms with unique formUrls
document.addEventListener('DOMContentLoaded', (e) => {
  var deleteButtons = document.getElementsByClassName("delete-book");
  for (var index=0; index < deleteButtons.length; index++) {
    modalForm(deleteButtons[index], {
      formURL: deleteButtons[index]["dataset"]["formUrl"],
      isDeleteForm: true
    });
  }
});

</script>
  1. Click event on html element instantiated with modalForm opens modal
  2. Form at formURL is appended to the modal
  3. On submit the form is POSTed via AJAX request to formURL
  4. Unsuccessful POST request returns errors, which are shown in modal
  5. Successful POST request submits the form and redirects to success_url and shows success_message, which are both defined in related Django view

Usage

1. Form

Define BookModelForm and inherit built-in form BSModalModelForm.

forms.py

from .models import Book
from bootstrap_modal_forms.forms import BSModalModelForm

class BookModelForm(BSModalModelForm):
    class Meta:
        model = Book
        fields = ['title', 'author', 'price']

2. Form's html

Define form's html and save it as Django template.

  • Form will POST to formURL defined in #6.
  • 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.
book/create_book.html

<form method="post" action="">
  {% csrf_token %}

 <div class="modal-header">
    <h5 class="modal-title">Create new Book</h5>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">
    {% for field in form %}
      <div class="form-group{% if field.errors %} invalid{% endif %}">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {{ field }}
        {% for error in field.errors %}
          <p class="help-block">{{ error }}</p>
        {% endfor %}
      </div>
    {% endfor %}
  </div>

  <div class="modal-footer">
    <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
    <button type="submit" class="btn btn-primary">Create</button>
  </div>

</form>

3. 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.

views.py

from django.urls import reverse_lazy
from .forms import BookModelForm
from .models import Book
from bootstrap_modal_forms.generic import BSModalCreateView

class BookCreateView(BSModalCreateView):
    template_name = 'examples/create_book.html'
    form_class = BookModelForm
    success_message = 'Success: Book was created.'
    success_url = reverse_lazy('index')

4. URL for the view

Define URL for the view in #3.

from django.urls import path
from books import views

urlpatterns = [
    path('', views.Index.as_view(), name='index'),
    path('create/', views.BookCreateView.as_view(), name='create_book'),
]

5. Bootstrap modal and trigger element

Define the Bootstrap modal window and html element triggering modal opening.

  • Single modal can be used for multiple modalForms in single template (see #6).
  • 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.
  • Trigger element (in this example button with id="create-book") is used for instantiation of modalForm in #6.
  • Any element can be trigger element as long as modalForm is bound to it.
  • Click event on trigger element loads form's html from #2 within <div class="modal-content"></div> and sets action attribute of the form to formURL set in #6.
index.html

<div class="modal fade" tabindex="-1" role="dialog" id="modal">
  <div class="modal-dialog" role="document">
    <div class="modal-content"></div>
  </div>
</div>

<!-- Create book button -->
<button id="create-book" class="btn btn-primary" type="button" name="button">Create book</button>

6. 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.

  • 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.
  • 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.
index.html

<script type="text/javascript">

// BS4
$(document).ready(function() {
    $("#create-book").modalForm({
        formURL: "{% url 'create_book' %}"
    });
});

// BS5
document.addEventListener('DOMContentLoaded', (e) => {
  modalForm(document.getElementById('create-book'), {
    formURL: "{% url 'create_book' %}"
  })
});

</script>

Async create/update with or without modal closing on submit

Set 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. See examples on how to properly reinstantiate modal forms for all CRUD buttons when using async options.

index.html

<!-- asyncSettings.dataElementId -->
<table id="books-table" class="table">
  <thead>
    ...
  </thead>
  <tbody>
  {% for book in books %}
    <tr>
        ...
        <!-- Update book buttons -->
        <button type="button" class="update-book btn btn-sm btn-primary" data-form-url="{% url 'update_book' book.pk %}">
          <span class="fa fa-pencil"></span>
        </button>
        ...
      </td>
    </tr>
  {% endfor %}
  </tbody>
</table>

<script type="text/javascript">
    $(function () {
        ...

        # asyncSettings.successMessage
        var asyncSuccessMessage = [
          "<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.addModalFormFunction
        function updateBookModalForm() {
          $(".update-book").each(function () {
            $(this).modalForm({
              formURL: $(this).data("form-url"),
              asyncUpdate: true,
              asyncSettings: {
                closeOnSubmit: false,
                successMessage: asyncSuccessMessage
                dataUrl: "books/",
                dataElementId: "#books-table",
                dataKey: "table",
                addModalFormFunction: updateBookModalForm
              }
            });
          });
        }
        updateBookModalForm();

        ...
    });
</script>
urls.py

from django.urls import path
from . import views

urlpatterns = [
    ...
    # asyncSettings.dataUrl
    path('books/', views.books, name='books'),
    ...
]
views.py

from django.http import JsonResponse
from django.template.loader import render_to_string
from .models import Book

def books(request):
    data = dict()
    if request.method == 'GET':
        books = Book.objects.all()
        # asyncSettings.dataKey = 'table'
        data['table'] = render_to_string(
            '_books_table.html',
            {'books': books},
            request=request
        )
        return JsonResponse(data)

modalForm options

modalID
Sets the custom id of the modal. Default: "#modal"
modalContent
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"
modalForm
Sets the custom form selector. Default: ".modal-content form"
formURL
Sets the url of the form's view and html. Default: null
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" for Boostrap 4 and ".is-invalid" for Bootstrap 5.
asyncUpdate
Sets asynchronous content update after form submission. Default: false
asyncSettings.closeOnSubmit
Sets whether modal closes or not after form submission. Default: false
asyncSettings.successMessage
Sets successMessage shown after succesful for submission. Should be set to string defining message element. See asyncSuccessMessage example above. Default: null
asyncSettings.dataUrl
Sets url of the view returning new queryset = all of the objects plus newly created or updated one after asynchronous update. Default: null
asyncSettings.dataElementId
Sets the id of the element which rerenders asynchronously updated queryset. Default: null
asyncSettings.dataKey
Sets the key containing asynchronously updated queryset in the data dictionary returned from the view providing updated queryset. Default: null
asyncSettings.addModalFormFunction
Sets the method needed for reinstantiation of event listeners on buttons (single or all CRUD buttons) after asynchronous update. Default: null

modalForm default settings object and it's structure

triggerElement.modalForm({
    modalID: "#modal",
    modalContent: ".modal-content",
    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: {
        closeOnSubmit: false,
        successMessage: null,
        dataUrl: null,
        dataElementId: null,
        dataKey: null,
        addModalFormFunction: null
    }
});

Forms

Import forms with from bootstrap_modal_forms.forms import BSModalForm.

BSModalForm
Inherits PopRequestMixin and Django's forms.Form.
BSModalModelForm
Inherits PopRequestMixin, CreateUpdateAjaxMixin and Django's forms.ModelForm.

Mixins

Import mixins with from bootstrap_modal_forms.mixins import PassRequestMixin.

PassRequestMixin
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.
PopRequestMixin
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.
CreateUpdateAjaxMixin
ModelForm Mixin which passes or saves object based on request type.
DeleteMessageMixin
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.
FormValidationMixin
Generic View Mixin which saves object and redirects to success_url if request is not ajax request. Otherwise response 204 No content is returned.
LoginAjaxMixin
Generic View Mixin which authenticates user if request is not ajax request.

Generic views

Import generic views with from bootstrap_modal_forms.generic import BSModalFormView.

BSModalLoginView
Inhertis LoginAjaxMixin and Django's LoginView.
BSModalFormView
Inherits PassRequestMixin and Django's generic.FormView.
BSModalCreateView
Inherits PassRequestMixin, FormValidationMixin and generic.CreateView.
BSModalUpdateView
Inherits PassRequestMixin, FormValidationMixin and generic.UpdateView.
BSModalReadView
Inherits Django's generic.DetailView.
BSModalDeleteView
Inherits DeleteMessageMixin and Django's generic.DeleteView.

Examples

To see django-bootstrap-modal-forms in 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 runserver

Example 1: Signup form in Bootstrap modal

For explanation how all the parts of the code work together see paragraph Usage. To test the working solution presented here clone and run Examples.

forms.py

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from bootstrap_modal_forms.mixins import PopRequestMixin, CreateUpdateAjaxMixin


class CustomUserCreationForm(PopRequestMixin, CreateUpdateAjaxMixin,
                             UserCreationForm):
    class Meta:
        model = User
        fields = ['username', 'password1', 'password2']
signup.html

{% load widget_tweaks %}

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Sign up</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">

    <div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
      {% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}
    </div>

    {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {% render_field field class="form-control" placeholder=field.label %}
        <div class="{% if field.errors %} invalid{% endif %}">
          {% for error in field.errors %}
            <p class="help-block">{{ error }}</p>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>

  <div class="modal-footer">
    <button type="submit" class="btn btn-primary">Sign up</button>
  </div>

</form>
views.py

from django.urls import reverse_lazy
from bootstrap_modal_forms.generic import BSModalCreateView
from .forms import CustomUserCreationForm

class SignUpView(BSModalCreateView):
    form_class = CustomUserCreationForm
    template_name = 'examples/signup.html'
    success_message = 'Success: Sign up succeeded. You can now Log in.'
    success_url = reverse_lazy('index')
urls.py

from django.urls import path
from . import views

app_name = 'accounts'
urlpatterns = [
    path('signup/', views.SignUpView.as_view(), name='signup')
]
.html file containing modal, trigger element and script instantiating modalForm

<div class="modal fade" tabindex="-1" role="dialog" id="modal">
  <div class="modal-dialog" role="document">
    <div class="modal-content"></div>
  </div>
</div>

<button id="signup-btn" class="btn btn-primary" type="button" name="button">Sign up</button>

<script type="text/javascript">
  $(function () {
    // Sign up button
    $("#signup-btn").modalForm({
        formURL: "{% url 'signup' %}"
    });
  });
</script>

Example 2: Login form in Bootstrap modal

For explanation how all the parts of the code work together see paragraph Usage. To test the working solution presented here clone and run Examples.

You can set the login redirection by setting the LOGIN_REDIRECT_URL in settings.py.

You can also set the custom login redirection by:

  1. Adding success_url to the extra_context of CustomLoginView
  2. Setting this success_url variable as a value of the hidden input field with name="next" within the Login form html
forms.py

from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User

class CustomAuthenticationForm(AuthenticationForm):
    class Meta:
        model = User
        fields = ['username', 'password']
login.html

{% load widget_tweaks %}

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Log in</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">

    <div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
      {% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}
    </div>

    {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {% render_field field class="form-control" placeholder=field.label %}
        <div class="{% if field.errors %} invalid{% endif %}">
          {% for error in field.errors %}
            <p class="help-block">{{ error }}</p>
          {% endfor %}
        </div>
      </div>
    {% endfor %}

    <!-- Hidden input field for custom redirection after successful login -->
    <input type="hidden" name="next" value="{{ success_url }}">
  </div>

  <div class="modal-footer">
    <button type="submit" class="btn btn-primary">Log in</button>
  </div>

</form>
views.py

from django.urls import reverse_lazy
from bootstrap_modal_forms.generic import BSModalLoginView
from .forms import CustomAuthenticationForm

class CustomLoginView(BSModalLoginView):
    authentication_form = CustomAuthenticationForm
    template_name = 'examples/login.html'
    success_message = 'Success: You were successfully logged in.'
    extra_context = dict(success_url=reverse_lazy('index'))
urls.py

from django.urls import path
from . import views

app_name = 'accounts'
urlpatterns = [
    path('login/', views.CustomLoginView.as_view(), name='login')
]
.html file containing modal, trigger element and script instantiating modalForm

<div class="modal fade" tabindex="-1" role="dialog" id="modal">
  <div class="modal-dialog" role="document">
    <div class="modal-content"></div>
  </div>
</div>

<button id="login-btn" class="btn btn-primary" type="button" name="button">Sign up</button>

<script type="text/javascript">
  $(function () {
    // Log in button
    $("#login-btn").modalForm({
        formURL: "{% url 'login' %}"
    });
  });
</script>

Example 3: Django's forms.ModelForm (CRUD forms) in Bootstrap modal

For explanation how all the parts of the code work together see paragraph Usage. To test the working solution presented here clone and run Examples.

forms.py

from .models import Book
from bootstrap_modal_forms.forms import BSModalModelForm


class BookModelForm(BSModalModelForm):
    class Meta:
        model = Book
        exclude = ['timestamp']
create_book.html

{% load widget_tweaks %}

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Create Book</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">

    <div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
      {% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}
    </div>

    {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {% render_field field class="form-control" placeholder=field.label %}
        <div class="{% if field.errors %} invalid{% endif %}">
          {% for error in field.errors %}
            <p class="help-block">{{ error }}</p>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>

  <div class="modal-footer">
    <button type="submit" class="btn btn-primary">Create</button>
  </div>

</form>
update_book.html

{% load widget_tweaks %}

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Update Book</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">
    <div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
      {% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}
    </div>

    {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {% render_field field class="form-control" placeholder=field.label %}
        <div class="{% if field.errors %} invalid{% endif %}">
          {% for error in field.errors %}
            <p class="help-block">{{ error }}</p>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>

  <div class="modal-footer">
    <button type="submit" class="btn btn-primary">Update</button>
  </div>

</form>
read_book.html

{% load widget_tweaks %}

<div class="modal-header">
  <h3 class="modal-title">Book details</h3>
  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
    <span aria-hidden="true">&times;</span>
  </button>
</div>

<div class="modal-body">
  <div class="">
    Title: {{ book.title }}
  </div>
  <div class="">
    Author: {{ book.author }}
  </div>
  <div class="">
    Price: {{ book.price }} €
  </div>
</div>

<div class="modal-footer">
  <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
{% load widget_tweaks %}

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Delete Book</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">
    <p>Are you sure you want to delete book with title
      <strong>{{ book.title }}</strong>?</p>
  </div>

  <div class="modal-footer">
    <button type="submit" class="btn btn-danger">Delete</button>
  </div>

</form>
views.py

from django.urls import reverse_lazy
from django.views import generic
from .forms import BookModelForm
from .models import Book
from bootstrap_modal_forms.generic import (
  BSModalCreateView,
  BSModalUpdateView,
  BSModalReadView,
  BSModalDeleteView
)

class Index(generic.ListView):
    model = Book
    context_object_name = 'books'
    template_name = 'index.html'

# Create
class BookCreateView(BSModalCreateView):
    template_name = 'examples/create_book.html'
    form_class = BookModelForm
    success_message = 'Success: Book was created.'
    success_url = reverse_lazy('index')

# Update
class BookUpdateView(BSModalUpdateView):
    model = Book
    template_name = 'examples/update_book.html'
    form_class = BookModelForm
    success_message = 'Success: Book was updated.'
    success_url = reverse_lazy('index')

# Read
class BookReadView(BSModalReadView):
    model = Book
    template_name = 'examples/read_book.html'

# Delete
class BookDeleteView(BSModalDeleteView):
    model = Book
    template_name = 'examples/delete_book.html'
    success_message = 'Success: Book was deleted.'
    success_url = reverse_lazy('index')
urls.py

from django.urls import path
from books import views

urlpatterns = [
    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"-->
<div class="modal fade" id="create-modal" tabindex="-1" role="dialog" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
    </div>
  </div>
</div>

<!-- Modal 2 with id="modal" -->
<div class="modal fade" tabindex="-1" role="dialog" id="modal">
  <div class="modal-dialog" role="document">
    <div class="modal-content"></div>
  </div>
</div>

<!-- Create book button -->
<button id="create-book" class="btn btn-primary" type="button" name="button">Create book</button>

{% for book in books %}
    <div class="text-center">
      <!-- Read book buttons -->
      <button type="button" class="read-book bs-modal btn btn-sm btn-primary" data-form-url="{% url 'read_book' book.pk %}">
        <span class="fa fa-eye"></span>
      </button>
      <!-- Update book buttons -->
      <button type="button" class="update-book bs-modal btn btn-sm btn-primary" data-form-url="{% url 'update_book' book.pk %}">
        <span class="fa fa-pencil"></span>
      </button>
      <!-- Delete book buttons -->
      <button type="button" class="delete-book bs-modal btn btn-sm btn-danger" data-form-url="{% url 'delete_book' book.pk %}">
        <span class="fa fa-trash"></span>
      </button>
    </div>
{% endfor %}

<script type="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 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.
  • These data-form-url URLs should than be set as formURLs for modalForms bound to the buttons.

Example 4: Django's forms.Form in Bootstrap modal

For explanation how all the parts of the code work together see paragraph Usage. To test the working solution presented here clone and run Examples.

forms.py

from bootstrap_modal_forms.forms import BSModalForm

class BookFilterForm(BSModalForm):
    type = forms.ChoiceField(choices=Book.BOOK_TYPES)

    class Meta:
        fields = ['type']
filter_book.html

{% load widget_tweaks %}

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Filter Books</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">
    <div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
      {% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}
    </div>

    {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {% render_field field class="form-control" placeholder=field.label %}
        <div class="{% if field.errors %} invalid{% endif %}">
          {% for error in field.errors %}
            <p class="help-block">{{ error }}</p>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>

  <div class="modal-footer">
    <button type="submit" class="btn btn-primary">Filter</button>
  </div>

</form>
views.py

class BookFilterView(BSModalFormView):
    template_name = 'examples/filter_book.html'
    form_class = BookFilterForm

    def form_valid(self, form):
        self.filter = '?type=' + form.cleaned_data['type']
        response = super().form_valid(form)
        return response

    def get_success_url(self):
        return reverse_lazy('index') + self.filter
urls.py

from django.urls import path
from . import views

app_name = 'accounts'
urlpatterns = [
    path('filter/', views.BookFilterView.as_view(), name='filter_book'),
]
index.html

  ...
  <button id="filter-book" class="filter-book btn btn-primary" type="button" name="button" data-form-url="{% url 'filter_book' %}">
    <span class="fa fa-filter mr-2"></span>Filter books
  </button>
  ...

  <script type="text/javascript">
    $(function () {
      ...
      $("#filter-book").each(function () {
          $(this).modalForm({formURL: $(this).data('form-url')});
      });
      ...
    });
  </script>

License

This project is licensed under the MIT License.

django-bootstrap-modal-forms's People

Contributors

christianwgd avatar comfix avatar dependabot[bot] avatar sebastiendementen avatar trco avatar virdiignis avatar willowmist avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-bootstrap-modal-forms's Issues

sorry,i cannot install your app ,i'm using Windows.

here are my errors
ERROR: Command errored out with exit status 1:
command: 'e:\pntmes\venv\scripts\python.exe' -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'C:\Users\JKKING\AppData\Local\Temp\pip-install-zmuke_pt\django-bootstrap-modal-forms\setup.py'"'"'; __
file__='"'"'C:\Users\JKKING\AppData\Local\Temp\pip-install-zmuke_pt\django-bootstrap-modal-forms\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(file);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'
"'"');f.close();exec(compile(code, file, '"'"'exec'"'"'))' egg_info --egg-base pip-egg-info
cwd: C:\Users\JKKING\AppData\Local\Temp\pip-install-zmuke_pt\django-bootstrap-modal-forms
Complete output (5 lines):
Traceback (most recent call last):
File "", line 1, in
File "C:\Users\JKKING\AppData\Local\Temp\pip-install-zmuke_pt\django-bootstrap-modal-forms\setup.py", line 5, in
README = readme.read()
UnicodeDecodeError: 'gbk' codec can't decode byte 0xac in position 19230: illegal multibyte sequence
----------------------------------------
ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.

Support updating of queryset objects

Update formURL setup during modalForm instatiation to dynamically set form's action attribute and thus add possibility to update objects using Django UpdateView or custom function based views.

Send newly created pk from createview to readview

I'm trying to set up the following flow:

  • In CreateView modal, user clicks "next" (create / submit button)
  • ReadView modal appears, using pk from newly created object
  • When user clicks button in ReadView, I need to make an update on the backend as I did in CreateView (to change prescription.status). I'd like the data to be uneditable in the ReadView display, so I'm trying to use ReadView instead of UpdateView.

So far I can make Createview appear and save data successfully on button click, but then I have a redirect to a new page instead of a second modal:

views.py

class PrescriptionCreateView(BSModalCreateView):
    template_name = 'myapp/create_prescription.html'
    form_class = PrescriptionForm

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.status = Prescription_status.objects.get(pk=1) # draft status
        self.object.practice = self.request.user.practice # practice id
        self.object.save()
        return redirect('read_prescription', pk=self.object.myapp_order_id)

class PrescriptionReadView(BSModalReadView):
    model = Prescription
    template_name = 'myapp/read_prescription.html'

forms.py

class PrescriptionForm(BSModalForm):
    class Meta:
        model = Prescription
        fields = ['prescriber', 'medication', 'quantity', 'directions', 'refills', 'earliest_permitted_fill_date', 'daw',]
        widgets = {
             'earliest_permitted_fill_date': DatePickerInput(), # default date-format %m/%d/%Y will be used
         }

    def __init__(self, *args, **kwargs):
        super(PrescriptionForm, self).__init__(*args, **kwargs)
        self.fields['prescriber'].queryset = CustomUser.objects.filter(practice=self.request.user.practice, prescriber=False)

urls.py

urlpatterns = [
    path('', views.index, name='index'),
    path('login', views.login_view, name='login'),
    path('logout', views.logout_view, name='logout'),
    path('password_reset', views.passwordreset, name='password_reset'),
    path('help', views.help, name='help'),
    path('vhome', views.vhome, name='vhome'),
    path('create', views.PrescriptionCreateView.as_view(), name='create_prescription'),
    path('read/<int:pk>', views.PrescriptionReadView.as_view(), name='read_prescription'),
   ]

read_prescription.html

{% block extrahead %}
{% load crispy_forms_tags %}
{% load widget_tweaks %}
{% endblock %}

<div class="modal-header">
  <h3 class="modal-title">Confirm RX Details</h3>
  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
    <span aria-hidden="true">&times;</span>
  </button>
</div>

<div class="modal-body">

  <div class="">
    Prescriber:
    {{ prescription.prescriber }}
  </div>
  <div class="">
    Medication:
    {{ prescription.medication }}
  </div>
  <div class="">
    Quantity:
    {{ prescription.quantity }}
  </div>
  <div class="">
    Directions:
    {{ prescription.directions }}
  </div>
  <div class="">
    Refills:
    {{ prescription.refills }}
  </div>
  <div class="">
    Earliest Permitted Fill Date:
    {{ prescription.earliest_permitted_fill_date }}
  </div>
  <div class="">
    DAW:
    {{ prescription.daw }}
  </div>


</div>

<div class="modal-footer">
  <button type="button" class="btn btn-default" data-dismiss="modal">Save</button>
</div>

vhome.html (page where modals need to pop up)

{% extends 'myapp/base.html' %}

{% block content %}

    {% include "myapp/_modal.html" %}

    <!-- django-bootstrap-modal-forms plugin code -->
    <button class="create-prescription btn btn-primary" type="button" name="button"><span class="fa fa-plus mr-2"></span>Create Prescription</button>

{% endblock content %}


{% block extrascripts %}
  <script type="text/javascript">
     $(document).ready(function() {
      // Create button
      $(".create-prescription").modalForm({
          formURL: "{% url 'create_prescription' %}"});
      $(".read-book").each(function () {
      $(this).modalForm({formURL: $(this).data('id')});
    });
          // Update buttons
    $(".update-prescription").each(function () {
      $(this).modalForm({formURL: $(this).data('id')});
    });
      // Hide message
      $(".alert").fadeTo(2000, 500).slideUp(500, function(){
        $(".alert").slideUp(500);
      });
    });
  </script>

{% endblock extrascripts %}

This is really critical to my app so I'm hoping it's possible. Thank you in advance and I promise this is my last question!

"create" modal function wont work after moving all js urls declaration to an external .js file

Hi Uroš,

As my project gets bigger and bigger and having a lots of models wich means a lots .modalForm JS URLS ... I moved all my js declaration URLS into .js file, everything works fine, except all create funtctions wont work for I don't know what reason,

Here the console django log for the "maintenance create" with is coded as :
.js :

$(".create-maintenance").modalForm({formURL: "{% url 'maintenance:create_maintenance' %}"});:

urls.py :

path('create_modal/', views.MaintenanceCreateModal.as_view(), name='create_maintenance'),

Not Found: /vehicule/maintenance/{%
[14/Dec/2018 22:46:02] "GET /vehicule/maintenance/%7B% HTTP/1.1" 404 7443

I made the create js declaration and the html link to it as the other CRUD function (update, read, delete), like this :

.js :

rather than this :

$(".create-maintenance").modalForm({formURL: "{% url 'maintenance:create_maintenance' %}"});

I change it to this :

$(".create-maintenance").each(function () {
	$(this).modalForm({formURL: $(this).data('id')});
});

.html:

rather than this :

<a href="javascript:;" class="create-maintenance">New maintenance</a>

I change it to this :

<a href="javascript:;" class="create-maintenance" data-id="{% url 'maintenance:create_maintenance' %}">New maintenance</a>

and it is WORKING VERY WELL

My question is : is this a bad practice?, is it ok to let it as it is ?, Is it great ??, is this the worst way to do it ?

Thank you.

SucessURL not Working for BSModaDeleteView

I have a different aproach because the foreign key relations. I'm using the modal to crud different models related with the Parent model.
After study a lot I did the correct reference to pass variables of the differents PK (between the parent and foreing key) etc etc.

But I get a strange behavior using the same script to delete.

Both EDIT and DELETE the succesURL behavior is going back to the Parent editing page.
The edit is working, but the DELETE is not, is trying to go to the Delete form page for a non existent object (because obviously is deleted).


# --- views.py

class PerfilEdit(BSModalUpdateView):
	model = Perfil
	template_name = 'projeto/perfil_add.html'
	form_class = PerfilEditForm

	def get_success_url(self):
		return reverse_lazy('projeto_edit', kwargs={'pk': self.kwargs.get('projeto_pk')})


class PerfilDelete(BSModalDeleteView):
	model = Perfil
	template_name = 'projeto/perfil_del.html'
	success_message = 'Perfil excluído'

	def get_success_url(self):
		return reverse_lazy('projeto_edit', kwargs={'pk': self.kwargs.get('projeto_pk')})

# --- urls.py
	path('perfil_edit/<pk>/<int:projeto_pk>', PerfilEdit.as_view(), name='perfil_edit'),
	path('perfil_del/<pk>/<int:projeto_pk>', PerfilDelete.as_view(), name='perfil_del'),

#--- template
# --- Buttons
<button class="btn-xs btn-success edit_perfil" type="button" data-id="{% url 'perfil_edit' i.pk projeto_id %}"><i class="fa fa-edit"></i> <span>Editar</span></button>
<button class="btn-xs btn-danger del_perfil" type="button" data-id="{% url 'perfil_del' i.pk projeto_id %}"><i class="fa fa-trash"></i> <span>Excluir</span></button>

# --- script
        $(".edit_perfil").each(function(){
            $(this).modalForm({
                formURL: $(this).data('id'),
            });
         });
        $(".del_perfil").each(function(){
            $(this).modalForm({
                formURL: $(this).data('id'),
            });
         });


#--- url trying after success sample:
http://127.0.0.1:8000/projetos/perfil_del/17/1

Django validation

After playing arround, It appears that the djago validation forms doesn't display in the botstrap modal, any idea how to activate it or fix it ?

thank 's

Modal opening in blank page after cancel

Hi, thanks for your project.

There seems to be a problem when you cancel the modal and then click the activation button again. The first time round the modal opens correctly, but the second time round it opens in a new blank page.

Regards

LoginView not using success_url

I'm not sure if this is a clone of #2 or #3 but I can't get the CustomLoginView success_url property to work to redirect after a login. Adding debug prints to the code using your example Django project, it seems the actual redirection is performed using the hard coded LOGIN_REDIRECT_URL = '/' in the settings.py. Setting the success_url to any value has no effect on this process.

Also the current version 1.3.1 of the jquery.bootstrap.modal.forms.js seems to lack the successURL competely while the previous versions still processed it. Does this mean the feature is currently broken or am I missing something?

Javascript inactive after first submit

Any extra javascript I have in the modal seems to become inactive after the user submits the form for the first time.

For instance, if I add a datepicker to one of the fields, but the user simply deletes the contents of the field (to make it invalid) and clicks submit, the form displays an error but the field no longer has a datepicker on it.

Duplicate record saved

Hi there,

Everything was running smoothly the last time I worked on my code, but for some reason when I went back to it today and clicked submit on the Create modal, it saves two records. Could you help me understand the issue? Thank you in advance!

_modal.html

<div class="modal fade" tabindex="-1" role="dialog" id="modal">
    <div class="modal-dialog" role="document">
      <div class="modal-content"></div>
    </div>
  </div>

create_prescription.html

{% block extrahead %}
{{ form.media }}            {# Adds date-picker required JS and CSS #}
{% load crispy_forms_tags %}
{% load widget_tweaks %}
{% endblock extrahead %}   

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Create Prescription</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">

    <div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
      {% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}
    </div>

    {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {% render_field field class="form-control" placeholder=field.label %}
        <div class="{% if field.errors %} invalid{% endif %}">
          {% for error in field.errors %}
            <p class="help-block">{{ error }}</p>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>

  <div class="modal-footer">
    <button type="button" class="submit-btn btn btn-primary">Next</button>
  </div>

</form>

vhome.html (page on which both modal and datatable are displayed)

{% extends 'app/main/base.html' %}

{% block extracss %}
<link rel="stylesheet" type="text/css" href="static/assets/DataTables/datatables.css"/>
{% endblock extracss %}


{% block content %}
{% include "app/veterinary/snippets/_modal.html" %}
{% include "app/veterinary/snippets/rxtable.html" %}
{% endblock content %}

{% block extrascripts %}
<script type="text/javascript" src="static/assets/DataTables/datatables.min.js"></script>

<script type="text/javascript">
    $(document).ready(function() {
    // Create button
    $(".create-prescription").modalForm({
      formURL: "{% url 'create_prescription' %}"});

    // Update buttons
    $(".update-prescription").each(function () {
      $(this).modalForm({formURL: $(this).data('id')});
    });

    // Read book buttons
    $(".read-prescription").each(function () {
      $(this).modalForm({formURL: $(this).data('id')});
    });

    // Delete book buttons
    $(".delete-prescription").each(function () {
      $(this).modalForm({formURL: $(this).data('id')});
    });

  });

$(document).ready( function () {
  $('#vrxTable').DataTable({
  "order": [[ 6, "desc" ]],
  "paging": false,
  "info": false,
  "searching": false,
  "columnDefs": [ {
    "targets": 0,
    "orderable": false
} ]
});
})
</script>

{% endblock extrascripts %}

views.py

@login_required(login_url="/login")
# Home (Logged In Dashboard) page view
def vhome(request):
    prescription_table = Prescription.objects.filter(veterinary_practice = request.user.veterinary_practice) # veterinary practice id
    context = {'prescription_table': prescription_table}
    return render(request, 'app/veterinary/vhome.html', context)

class PrescriptionCreateView(BSModalCreateView):
    template_name = 'app/veterinary/snippets/create_prescription.html'
    form_class = PrescriptionForm

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.prescription_type = 'Prescriber-Initiated' # prescription type
        self.object.status = Prescription_status.objects.get(pk=2) # draft status
        self.object.veterinary_practice = self.request.user.veterinary_practice # veterinary practice id
        self.object.save()
        return redirect('vhome')

class PrescriptionReadView(BSModalReadView):
    model = Prescription
    template_name = 'app/veterinary/snippets/read_prescription.html'

forms.py

class PrescriptionForm(BSModalForm):
    class Meta:
        model = Prescription
        fields = ['patient', 'prescriber', 'medication', 'quantity', 'directions', 'refills', 'earliest_permitted_fill_date', 'daw',]
        widgets = {
             'earliest_permitted_fill_date': DatePickerInput(), # default date-format %m/%d/%Y will be used
         }

    def __init__(self, *args, **kwargs):
        super(PrescriptionForm, self).__init__(*args, **kwargs)
        self.fields['prescriber'].queryset = CustomUser.objects.filter(veterinary_practice=self.request.user.veterinary_practice, prescriber=True)

Compatibility with django-allauth

This package is perfect for a web app I'm working on, specifically for user signup and login. However, I have been using django-allauth for my project so far in order to require only emails and not usernames for accounts.

I've had a go at following the signup example given in the documentation, which worked great, but I'm having trouble getting it to work with allauth. From other digging online I've seen suggestions allauth doesn't really work with modals. Does that apply to this package too?

Inline Formset is 'NoneType' object

I am having issues with adding inline formsets to my forms. When I fill in only the original form, everything works as expected. When I add information into the inline formset I get:

Traceback:

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  126.                 response = self.process_exception_by_middleware(e, request)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  124.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/views/generic/base.py" in view
  68.             return self.dispatch(request, *args, **kwargs)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/views/generic/base.py" in dispatch
  88.         return handler(request, *args, **kwargs)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  172.         return super().post(request, *args, **kwargs)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/views/generic/edit.py" in post
  142.             return self.form_valid(form)

File "/Users/jc/Documents/dev_env/tera/emc/views.py" in form_valid
  64.                 projectimages.save()

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/forms/models.py" in save
  669.         return self.save_existing_objects(commit) + self.save_new_objects(commit)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/forms/models.py" in save_new_objects
  803.             self.new_objects.append(self.save_new(form, commit=commit))

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/django/forms/models.py" in save_new
  945.         obj = form.save(commit=False)

File "/Users/jc/Documents/dev_env/lib/python3.6/site-packages/bootstrap_modal_forms/mixins.py" in save
  41.         if not self.request.is_ajax():

Exception Type: AttributeError at /project/add/
Exception Value: 'NoneType' object has no attribute 'is_ajax'

My view.py:

class ProjectCreate(BSModalCreateView):
    form_class = ProjectForm
    template_name = 'project_form.html'
    success_message = 'Success: %(project_name)s was created.'

    def get_success_url(self):
        return reverse_lazy('project-detail', kwargs={'project': self.object.slug})

    def get_context_data(self, **kwargs):
        data = super(ProjectCreate, self).get_context_data(**kwargs)
        if self.request.POST:
            data['projectimages'] = ProjectFormSet(self.request.POST, self.request.FILES,)
        else:
            data['projectimages'] = ProjectFormSet()
        return data

    def form_valid(self, form):
        form.instance.date_created = timezone.now()
        context = self.get_context_data()
        projectimages = context['projectimages']
        with transaction.atomic():
            self.object = form.save()

            if projectimages.is_valid():
                projectimages.instance = self.object
                projectimages.save()
        
        return super(ProjectCreate, self).form_valid(form)

My forms.py:

class ProjectForm(BSModalForm):
    class Meta:
        model = Project
        exclude = ['date_created', 'slug']

ProjectFormSet = inlineformset_factory(
    Project,
    ProjectImage,
    can_delete=True,
    form=ProjectForm,
    extra=1,
)

My models.py

class Project(models.Model):
    project_name = models.CharField(max_length=100)
    date_created = models.DateTimeField('Created on')
    slug = models.SlugField(unique=True)
   
    def __str__(self):
        return self.project_name

    def save(self, *args, **kwargs):
        self.slug = slugify(str(self))
        super(Project, self).save(*args, **kwargs)

    def get_absolute_url(self):
        return reverse('project-list')

class ProjectImage(models.Model):
    image =  models.ImageField(verbose_name='Additional Images', upload_to=project_directory_path)
    project = models.ForeignKey(Project, on_delete=models.PROTECT)
    annotation = models.CharField(max_length=200, blank=True)

May be a jQuery conflict

Hi Uroš,

I know that this is not a good place to post this, but you are the only one that can help here, since you are the best person in position and also the author of the Django bootstrap modal that I'm using in my template.

Rather than telling about the conflict that I was facing, better for me to give you the link of the tempalte creator/developper where I talked about it in details and even gave screenshot so that you'll have a better idea about the conflict so that you can help..

here's the link my id : riterix :
themeforest

This is the brick of the project and it is the pillar, cause I have 9 apps inside that project it all based on CRUD stuff from that Django Modal Form... Please.

Thank you for your help

Call the bootstrap Modal with dimension in option(large , small, ....)

Hi Uroš,

Based on the nature of the modal (Create, Delete, Update), some modals like delete in my case should be small, not all the CRUD modals the same size.

Is there a better/perfect way of comming up with a solution of having a bootstrap shows with a specific size based on the option gived in the its call ???

I've been scratching my head dins some but it bugs the project in somepoints ... any thoughts ??? what the best way of doing it ?

Thank you

django-bootstrap-modal-forms Triggered , fired up using Vuejs

Hi,

Is there a way to trigger/show that modal using Vuejs... ?
I'm talking about just the jQuery trigger function not the jQuery code that handles the modals code.

any ida ? coold that be possible to change jQuery trigger code to Vuejs ?

Thank's

Modal not opening

Hi there,

I'm trying to make a modal appear on my 'vhome.html' page, displaying the create format for my "Prescription" model. When I click the Create Prescription button on 'vhome.html', the screen goes gray as it should but only a small line appears at the top of the screen.

I've been looking at this for hours and I can't figure it out. Thank you in advance for your help.

forms.py

from django import forms
from .models import *
from bootstrap_datepicker_plus import DatePickerInput
from bootstrap_modal_forms.forms import BSModalForm


class PrescriptionForm(BSModalForm):
    class Meta:
        model = Prescription
        fields = ['prescriber',]

views.py

...
from django.shortcuts import render, redirect
from django import forms
from .models import *
from .forms import *
from bootstrap_modal_forms.generic import BSModalCreateView
from django.urls import reverse_lazy


class PrescriptionCreateView(BSModalCreateView):
    template_name = 'create_prescription.html'
    form_class = PrescriptionForm
    success_message = 'Success: Prescription was created.'
    success_url = reverse_lazy('vhome')

urls.py

from django.contrib import admin
from django.urls import path
from .import views
from django.contrib.auth import views as auth_views

urlpatterns = [
    path('', views.index, name='index'),
    path('vhome', views.vhome, name='vhome'),
    path('create/', views.PrescriptionCreateView.as_view(), name='create_prescription'),
   ]

settings.py

INSTALLED_APPS = [
...
    'bootstrap4',
    'crispy_forms',
    'bootstrap_datepicker_plus',
    'bootstrap_modal_forms',
    'widget_tweaks',
]

_modal.html

<div class="modal fade" tabindex="-1" role="dialog" id="modal">
    <div class="modal-dialog" role="document">
      <div class="modal-content"></div>
    </div>
  </div>

create_prescription.html

{% load widget_tweaks %}

<form method="post" action="">
  {% csrf_token %}

  <div class="modal-header">
    <h3 class="modal-title">Create Prescription</h3>
    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
      <span aria-hidden="true">&times;</span>
    </button>
  </div>

  <div class="modal-body">

    <div class="{% if form.non_field_errors %}invalid{% endif %} mb-2">
      {% for error in form.non_field_errors %}
        {{ error }}
      {% endfor %}
    </div>

    {% for field in form %}
      <div class="form-group">
        <label for="{{ field.id_for_label }}">{{ field.label }}</label>
        {% render_field field class="form-control" placeholder=field.label %}
        <div class="{% if field.errors %} invalid{% endif %}">
          {% for error in field.errors %}
            <p class="help-block">{{ error }}</p>
          {% endfor %}
        </div>
      </div>
    {% endfor %}
  </div>

  <div class="modal-footer">
    <button type="button" class="submit-btn btn btn-primary">Create</button>
  </div>

</form>

base.html

{% load static %}

{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}


{% block extrahead %}
{{ form.media }} 
{% endblock %}


<!doctype html>
<html lang="en">
  <head>
    <title>myapp</title>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=yes">

    {% block stylesheets %}
    <!-- BEGIN PLUGINS STYLES -->
    <!-- plugins styles goes here -->
    <link rel="stylesheet" href="static/assets/css/bootstrap.css">
    <!-- END PLUGINS STYLES -->

    <!-- BEGIN THEME STYLES -->
    <link rel="stylesheet" href="static/assets/stylesheets/theme.min.css" data-skin="default">
    <link rel="stylesheet" href="static/assets/stylesheets/theme-dark.min.css" data-skin="dark">
    <link rel="stylesheet" href="static/assets/stylesheets/custom.css">

    <!-- Disable unused skin immediately -->
    <script>
      var skin = localStorage.getItem('skin') || 'default';
      var unusedLink = document.querySelector('link[data-skin]:not([data-skin="'+ skin +'"])');

      unusedLink.setAttribute('rel', '');
      unusedLink.setAttribute('disabled', true);
    </script>
    <!-- END THEME STYLES -->

    <!-- BEGIN PAGE LEVEL STYLES -->
    <!-- styles for specific page goes here -->
    <!-- END PAGE LEVEL STYLES -->
    {% endblock stylesheets %}


  </head>
  <body>
  <!-- .app -->
<div class="app">
  
  
  <!-- .app-header -->
  <header class="app-header app-header-light">
      
    
    <!-- .top-bar -->
      <div class="top-bar"
        <!-- .top-bar-brand -->
        <div class="top-bar-brand">
          <img src="{% static 'assets/images/color_logo_no_background.png' %}" class="px-3" height="50px" alt="">
        </div>
        <!-- /.top-bar-brand -->

        <!-- .top-bar-list -->
          <div class="top-bar-list">
                    
          <!-- .top-bar-item -->
          {% if 'vhome' in request.path %}
          <div class="top-bar-item top-bar-item-full">
            <!-- .top-bar-search -->
            <div class="top-bar-search px-3">
              <div class="input-group input-group-search">
                <div class="input-group-prepend">
                  <span class="input-group-text">
                    <span class="oi oi-magnifying-glass"></span>
                  </span>
                </div>
                <input type="text" class="form-control" aria-label="Search" placeholder="Search">
              </div>
            </div>
            <!-- /.top-bar-search -->
          </div>
          <!-- /.top-bar-item -->
          {% endif %}
<!-- .top-bar-item -->
<div class="top-bar-item top-bar-item-right px-3 d-none d-sm-flex">
  <!-- .nav -->
  <ul class="header-nav nav">
    <!-- .nav-item -->
    <li class="nav-item">
      <a class="nav-link" href="#">
        <span class="oi oi-grid-three-up"></span>
      </a>
    </li>
    <!-- /.nav-item -->
  </ul>
  <!-- /.nav -->
  <!-- .btn-account -->
  <div class="dropdown">
      <button class="btn-account d-none d-md-flex" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
        <span class="account-summary pr-lg-8 d-none d-lg-block">
            {% if request.user.is_authenticated %}
          <span class="account-name">Welcome, {{ request.user.first_name }}</span>
          <span class="account-description">{{ request.user.practice.business_name }}</span>
        </span>
      </button>
      <!-- .dropdown-menu -->
      <div class="dropdown-menu">
        <div class="dropdown-arrow"></div>
        <a class="dropdown-item" href="/vhome"><span class="dropdown-icon oi oi-home"></span> Dashboard</a>
        <a class="dropdown-item" href="/help"><span class="dropdown-icon oi oi-help"></span> Help</a>
        <div class="dropdown-divider"></div>
        <form class="logout-link" action="{% url 'logout' %}" method="POST">
            <span class="dropdown-icon oi oi-help"></span>
          {% csrf_token %}
          <button type="submit" class="btn btn-logout text-center"> Log Out</button>
        </form>
      </div>
      {% endif %}
      <!-- /.dropdown-menu -->
    </div>
    <!-- /.btn-account -->
  </div>
  

<!-- /.top-bar-item -->
</div>
<!-- /.top-bar-list -->
</div>
<!-- /.top-bar -->
</header>



<!-- .app-main -->
  <main class="app-main">
    <!-- .wrapper -->
    <div class="wrapper">
  <!-- your awesome app content goes here -->
    <!-- .page -->
    {% block content %}
    {% endblock %}
    <!-- /.page -->
  </div>
  <!-- /.wrapper -->
</main>
<!-- /.app-main -->
</div>
<!-- /.app -->


    {% block scripts %}
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <!-- BEGIN BASE JS -->
    <script src="{% static 'assets/js/jquery-3.2.1.min.js' %}"></script>
    <script src="{% static 'assets/vendor/bootstrap/js/popper.min.js' %}"></script>
    <script src="{% static 'assets/js/bootstrap.js' %}"></script>

    <!-- BEGIN PLUGINS JS -->
    <script src="{% static 'assets/vendor/stacked-menu/stacked-menu.min.js' %}"></script>
    <script src="{% static 'js/jquery.bootstrap.modal.forms.js' %}"></script>
    <!-- END PLUGINS JS -->

    <!-- BEGIN THEME JS -->
    <script src="{% static 'assets/javascript/theme.min.js' %}"></script>
    <!-- END THEME JS -->

    <!-- BEGIN PAGE LEVEL JS -->
    <!-- your js for specific page goes here -->
    <!-- END PAGE LEVEL JS -->
    {% endblock scripts %}

    {% block extrascripts %}
    {% endblock extrascripts %}
  
  
  
  </body>
</html>

vhome.html

{% extends 'myapp/base.html' %}

{% block content %}

    {% include "myapp/_modal.html" %}

    <!-- django-bootstrap-modal-forms plugin code -->
    <button class="create-prescription btn btn-primary" type="button" name="button"><span class="fa fa-plus mr-2"></span>Create Prescription</button>

{% endblock content %}


{% block extrascripts %}
  <script type="text/javascript">
     $(document).ready(function() {
      // Create button
      $(".create-prescription").modalForm({
          formURL: "{% url 'create_prescription' %}"});
      // Hide message
      $(".alert").fadeTo(2000, 500).slideUp(500, function(){
        $(".alert").slideUp(500);
      });
    });
  </script>
{% endblock extrascripts %}

no bound modelform

Hi, i did exactly as your steps,but "the field is required" error happend when i submit the form in modal by click the create button, how can i reslove it?

Implement this project otherthan CRUD Views

Hi.

The project implemented and works so far on CRUD Views.

But when I tried to implement it on Contact or Booking / Reservation view as a simple form without a model. the model it did show actuaaly but when I submit it shoot me an error :

Internal Server Error: /reservation/disponibilite_modal/ Traceback (most recent call last): File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/core/handlers/exception.py", line 34, in inner response = get_response(request) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/core/handlers/base.py", line 115, in _get_response response = self.process_exception_by_middleware(e, request) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/core/handlers/base.py", line 113, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/views/generic/base.py", line 71, in view return self.dispatch(request, *args, **kwargs) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/contrib/auth/mixins.py", line 85, in dispatch return super().dispatch(request, *args, **kwargs) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/views/generic/base.py", line 97, in dispatch return handler(request, *args, **kwargs) File "/home/rabah/dev/proveho/reservation/views.py", line 214, in post return super().form_invalid(form) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/views/generic/edit.py", line 61, in form_invalid return self.render_to_response(self.get_context_data(form=form)) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/views/generic/edit.py", line 67, in get_context_data return super().get_context_data(**kwargs) File "/home/rabah/.local/share/virtualenvs/proveho-G3NgZpUh/lib/python3.5/site-packages/django/views/generic/detail.py", line 94, in get_context_data if self.object: AttributeError: 'DisponibiliteVehiculeModal' object has no attribute 'object'

my forms.py :

class BookingForm(BSModalForm):

from_email = forms.EmailField(required=True)
subject = forms.CharField(required=True)
message = forms.CharField(widget=forms.Textarea, required=True)

class Meta:
	model = Reservation
	fields = '__all__'

my views.py :

class DisponibiliteVehiculeModal(PermissionRequiredMixin, BSModalCreateView):
permission_required = ('reservation.view_reservation',)

#model = Reservation

template_name = 'check_vehicule_disponible.html' #'reservation/create_reservation.html'
form_class = BookingForm #ReservationModalForm
#success_message = _("<strong>Reservation</strong> ajouté avec succés !.")
success_url = reverse_lazy('reservation:reservationList') #reverse_lazy('reservation:reservationList')


def post(self, request): #, *args, **kwargs

	form = self.get_form()
	if form.is_valid():
		request.session['_check_vehicule_disponible'] = request.POST
		#HttpResponseRedirect(reverse('reservation:vehiculeDisponibleList'))
		#return #HttpResponseRedirect(reverse('reservation:vehiculeDisponibleList'), kwargs={'product_id': 1})
		#return redirect('reservation:vehiculeDisponibleList', kwargs={'product_id': 1})
		
		base_url = reverse('reservation:vehiculeDisponibleList')  # 1 /products/
		query_string =  urlencode(
			{
				'from_email': request.POST.get('from_email'), 
				'subject': request.POST.get('subject'), 

				'message': request.POST.get('message'), 

			} 
		)  # 2 category=42
		
		url = '{}?{}'.format(base_url, query_string)  # 3 /products/?category=42
		return redirect(url)  # 4			
		
		
	else:
		return super().form_invalid(form)

Any idea how to use your modal bootsrap on regular form not CRUD form.

Just to let you know Uros that, It worked before the version 1.4 of your django-bootstrap-modal-forms
exactly version 1.3, I used FormView in my class , like that 👎

class DisponibiliteVehiculeModal(PermissionRequiredMixin, PassRequestMixin, FormView):

and in forms.py like that :

class BookingForm(PopRequestMixin, CreateUpdateAjaxMixin, forms.Form):

thank you uros.

Django-Select2 does not work.

Hi,

I implemented django-bootstrap-modal-forms and for some reason django-select2 drop down does not work. By any chance would you have a work around to make django-select to work with django-bootstrap-modal-forms?

I can't overload delete function in BSModalDeleteView

As BSDeleteModalView inherits DeleteView, I made a delete function for overloading ,
but nothing was happened when BSDeleteModalView is used.

the data I fetched to delete was surely deleted,
but it have done without delete function which I had made.

The source code is as below

class MemberDeleteModal(BSModalDeleteView,DeleteView):
    template_name='reportDeleteModalForm.html'
    model=Member
    
    success_message = 'SUCCESS'
    success_url = "/member"
    
   **#overloading DeleteView's delete function**
    def delete(self, request, *args, **kwargs):
        print("delete done")     # don't show this
        self.object = self.get_object()
        success_url = self.get_success_url()
        self.object.member_status=2
        return HttpResponseRedirect(success_url)
```


 

type="submit" vs type="button"?

Hey, thanks for publishing this. I can't quite get it to work but it looks like it'll do what I want.

I'm using your library to implement something almost exactly like your Example 2. However, when I follow it precisely (using type="button" in the Log in button) the submission never appears to be POSTed - when I click the Log in button nothing happens at all.

However, if I switch it to type="submit" and enter valid login credentials everything works as described.

The issue arises when I enter invalid login credentials. In that case, the user is redirected to login.html, which is missing all of the styling of my main webpage due to the fact that it's never actually meant to be rendered fully.

My questions are:

  • What is the purpose of using type="button" vs type="submit"?
  • Is there some method of making sure that, when invalid credentials are entered, the user is not redirected at all and instead the errors are shown with Bootstrap messages in the modal as your code intends?

Thanks!

Error 500

When I click the button that runs the function, I get a GET 500 error.
I followed the How To and did everything correctly, I think? What could be the cause of this?

Traceback:
File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\exception.py", line 34, in inner response = get_response(request) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response response = self.process_exception_by_middleware(e, request) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\views\generic\base.py", line 71, in view return self.dispatch(request, *args, **kwargs) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\contrib\auth\mixins.py", line 52, in dispatch return super().dispatch(request, *args, **kwargs) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\views\generic\base.py", line 97, in dispatch return handler(request, *args, **kwargs) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\views\generic\detail.py", line 106, in get self.object = self.get_object() File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\views\generic\detail.py", line 36, in get_object queryset = queryset.filter(pk=pk) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py", line 892, in filter return self._filter_or_exclude(False, *args, **kwargs) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\query.py", line 910, in _filter_or_exclude clone.query.add_q(Q(*args, **kwargs)) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\sql\query.py", line 1290, in add_q clause, _ = self._add_q(q_object, self.used_aliases) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\sql\query.py", line 1318, in _add_q split_subq=split_subq, simple_col=simple_col, File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\sql\query.py", line 1251, in build_filter condition = self.build_lookup(lookups, col, value) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\sql\query.py", line 1116, in build_lookup lookup = lookup_class(lhs, rhs) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\lookups.py", line 20, in __init__ self.rhs = self.get_prep_lookup() File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\lookups.py", line 70, in get_prep_lookup return self.lhs.output_field.get_prep_value(self.rhs) File "C:\Users\migas\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\db\models\fields\__init__.py", line 966, in get_prep_value return int(value) ValueError: invalid literal for int() with base 10: 'create'

Views.py:

from django.shortcuts import render
from django.urls import reverse, reverse_lazy
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from .models import EventCard, Task
from .forms import EventCardForm
from bootstrap_modal_forms.generic import BSModalCreateView 

@login_required
def home(request):
    events = EventCard.objects.all().filter(users__username=request.user.username)
    tasklist = {}
    for event in events:
        tasklist[event.event_name] = event.task_set.all().filter(users__username=request.user.username) 
    context = {'events': events, 'tasklist': tasklist}
    return render(request, 'board/home.html', context)

class EventListView(LoginRequiredMixin, ListView):
    model = EventCard
    template_name = 'board/events.html'
    context_object_name = 'events'
    ordering = ['date']

class EventDetailView(LoginRequiredMixin, DetailView):
    model = EventCard

class EventCreateView(LoginRequiredMixin, CreateView):
    model = EventCard
    fields = ['event_name', 'small_description', 'big_description', 'date', 'room']

    def form_valid(self, form):
        self.object = form.save()
        self.object.users.add(self.request.user)
        self.object.save()
        return super().form_valid(form)

class EventUpdateView(LoginRequiredMixin, UpdateView):
    model = EventCard
    fields = ['event_name', 'small_description', 'big_description', 'date', 'room']

    def form_valid(self, form):
        self.object = form.save()
        self.object.users.add(self.request.user)
        self.object.save()
        return super().form_valid(form)

class EventDeleteView(LoginRequiredMixin, DeleteView):
    model = EventCard
    success_url = '/home/events'

class ModalEventCreateView(BSModalCreateView):
    template_name = 'board/eventcard_form.html'
    form_class = 'EventCardForm'
    success_message = 'Success! Event was created!'
    success_url = reverse_lazy('events')

forms.py

from .models import EventCard
from bootstrap_modal_forms.forms import BSModalForm

class EventCardForm(BSModalForm):
    class Meta:
        model = EventCard
        fields = ['event_name', 'small_description', 'big_description', 'date', 'room']

urls.py:

from django.urls import path
from .views import EventListView, EventDetailView, EventCreateView, EventUpdateView, EventDeleteView, ModalEventCreateView
from . import views as board_views
from users import views as user_views
from django.conf.urls import url

urlpatterns = [
    path('', board_views.home, name = 'home'),
    path('events/', EventListView.as_view(), name = 'events'),
    path('profile/', user_views.profile, name = 'profile'),
    path('event/new/', EventCreateView.as_view(), name='event-create'),
    path('event/<pk>/update', EventUpdateView.as_view(), name='event-update'),
    path('event/<pk>/', EventDetailView.as_view(), name='event-detail'),
    path('event/<pk>/delete', EventDeleteView.as_view(), name='event-delete'),
    path('event/create/', board_views.ModalEventCreateView.as_view(), name='create-event')
]

How to add pk to success_url?

Hi again,
I know I'm annoying but I have another question, is there any way to add pk to success_url?

I am new into django and I do not know everything yet, so please be patient with my silly questions

Modal size

Hi Uroš,

As my project gets big, I realize that I needed a different modal size evertime I call the modal, not just a fixed size, I mean for example Create function of django app N°1 needs a normal size, but the Create function django app N°2 needs a (large) modal-lg size.

I've hacking around it, and I came up with this :

the diff of the .js file that I made

And the script in html :

...
...
$(".create-vehicule").modalForm({formURL: "{% url 'vehicule:create_vehicule' %}", modalSize: "modal-lg", successURL: "{% url 'vehicule:vehiculeList' %}"});

$(".update-vehicule").each(function () {
  $(this).modalForm({formURL: $(this).data('id'), modalSize: " ", successURL: "{% url 'vehicule:vehiculeList' %}"});
});

$(".delete-vehicule").each(function () {
  $(this).modalForm({formURL: $(this).data('id'), modalSize: "modal-sm", successURL: "{% url 'vehicule:vehiculeList' %}"});
});
...
...

it works fine, but after a while it stays at large size even if you call another smal function like delete . as I made it here...

could you take a look please..

It would be great if you integrate such an option Uroš, don't you thing it will give your project the dynamic way of choosing the modal depending on the function.!!!

thank you.

Problem with js file.

Hi,
So I have problem with jquery.bootstrap.modal.forms.js. When I click the button in a console appear sth like this:

Uncaught TypeError: $(...).load is not a function
    at newForm (jquery.bootstrap.modal.forms.js:5)
    at HTMLButtonElement.<anonymous> (jquery.bootstrap.modal.forms.js:66)
    at HTMLButtonElement.dispatch (jquery-3.3.1.slim.min.js:2)
    at HTMLButtonElement.v.handle (jquery-3.3.1.slim.min.js:2)

Can you help me with this?

Pass a variable to pre-populate field in form?

I've made a "create comment" modal form that can be activated from several locations. I'd like to pass a value for one of the comment fields to the form -- the id of the record instance they're looking at -- to save users the trouble of finding and copying it into an input box.

I see I can grab a variable and pass it as a data-id in the button, but what would the javascript modalForm function url look like? I tried replacing the create_comment url with $(this).data('id'), but I get a console error of "TypeError: e is null". Will this be doable?

BUTTON

<button type="button" class="create-comment btn btn-sm" 
     data-id="{{ form.authrecord_id.value }}">Add comment</button>

FUNCTION
$(".create-comment").modalForm({formURL: $(this).data('id')});

I installed this module but still have error "ModuleNotFoundError: No module named 'bootstrap_model_forms'"

Unhandled exception in thread started by <function check_errors..wrapper at 0x03E3DC90>
Traceback (most recent call last):
File "C:\Users\Local\Programs\Python\Python37-32\lib\site-packages\django\utils\autoreload.py", line 225, in wrapper
fn(*args, **kwargs)
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\management\commands\runserver.py", line 109, in inner_run
autoreload.raise_last_exception()
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\utils\autoreload.py", line 248, in raise_last_exception
raise exception[1]
File "C:\Usersr\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\core\management_init
.py", line 337, in execute
autoreload.check_errors(django.setup)()

File "C:\Usersr\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\utils\autoreload.py", line 225, in wrapper
fn(*args, **kwargs)
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django_init_.py", line 24, in setup
apps.populate(settings.INSTALLED_APPS)
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\apps\registry.py", line 89, in populate
app_config = AppConfig.create(entry)
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\site-packages\django\apps\config.py", line 90, in create
module = import_module(entry)
File "C:\Users\AppData\Local\Programs\Python\Python37-32\lib\importlib_init_.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "", line 1006, in _gcd_import
File "", line 983, in _find_and_load
File "", line 965, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'bootstrap_model_forms'
PS C:\Users\Documents\development-master\pcsite> pip install django-bootstrap-modal-forms
Requirement already satisfied: django-bootstrap-modal-forms in c:\users\appdata\local\programs\python\python37-32\lib\site-packages (1.0)
PS C:\Users\Documents\development-master\pcsite>

It shows that the package has been installed. I also put the
INSTALLED_APPS = [
...
'bootstrap_model_forms',
...
]

DeleteMessageMixin calls parent delete, removing possibility of implementing

In DeleteMessageMixin the parent's delete() is called

    def post(self, request, *args, **kwargs):
        messages.success(request, self.success_message)
        return super(DeleteMessageMixin, self).delete(request, *args, **kwargs)

which removes the possibility of implementing this in the View class itself. I would like to be able to do this to implement a 'virtual deletion' by setting a flag on the object to hide from the user's view while maintaining the object in the db. What would be against just doing

    return self.delete(request, *args, **kwargs)

as the parent's delete() will be used anyway if the View didn't implement it?

Custom errorClass breaks Modal

Greetings, just started using this project today, great job!

I have ran in to one issue that I can reproduce constantly. If I provide a 'errorClass' argument the Modal will open as normal, but when I click Submit it opens a new page with the modal content and invalid states on there, completely ignoring my errorClass. If I delete the errorClass argument then everything goes back to working like normal.

$(".create-timeentry").each(function () { $(this).modalForm({ formURL: $(this).attr("data-url"), errorClass: '.error' }); });

I used your sample 'create_book' code, if I change the '{% if field.errors %} invalid{% endif %}' to '{% if field.errors %} error{% endif %}' it does the same thing

BUT, if I change it to {% if field.errors %} invalid error{% endif %} then my error class is applied as it should.

Thanks!

Integrate Django messages

Currently the redirection after successful form submission prevents Django messages to work normally.

Modal content not adding bootstrap classes, placeholder text

Love the library, super easy to get plugged into a project and very easy to use.

I did have one question and it's probably from my end but wasn't sure what I was missing. I followed the directions to implement a simple create operation in a modal based a on model and everything works correctly. The only problem is that my form isn't getting some bootstrap elements such as placeholder="Title" or class="form-control". Am I missing something stupid?

Question

in the case of the example book application, is there any way to show success_message, and update the table with the inserted record without refreshing the page?

Another (image) modal in same template is causing duplicate form saving

I have been fighting to stop each time I submit a form, it saving two instances. I noticed #14 but I see 4 POST entries in django's logging when I submit the form.

After trying a lot of different things in the views and forms etc., I looked in the templates. I have the following:

    <!-- show images modal -->
    <div class="modal fade" id="imagemodal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-body">
                    <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
                    <img src="" class="imagepreview" style="width:100%">
                </div>
            </div>
        </div>
    </div>

Which pops up an image in my page, when clicked, using:

    <script>
        $(function() {
            $('.pop').on('click', function() {
                $('.imagepreview').attr('src', $(this).find('img').attr('src'));
                });
        });
    </script>

When I comment out the imagemodal div my form works as intended thus I suspect there is some conflict here.

It doesn't seem like a bug as such, but I was wondering if it was able to have these (very nice) form modals play nicely with existing modals in the template?

Thanks,

Update the image field

I was trying to update my view but got some problem with image field. It didn't update. How can I fix it? I don't get any errors.

models.py

from django.db import models
from django.conf import settings
from django.utils import timezone
from PIL import Image

def save_image_path(instance, filename):
    filename = instance.image
    return 'profile_pics/{}/{}'.format(instance.user.username, filename)

class Subscriber(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, unique=True, related_name = 'user')
    city = models.CharField(max_length = 25)
    country = models.CharField(max_length = 25)
    birthday = models.DateField(blank = True)
    image = models.ImageField(default='default.jpg', upload_to=save_image_path)

    def __str__(self):
        return self.user.username

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        # resize of image
        img = Image.open(self.image.path)
        if img.height > 300 or img.width > 300:
            output_size = (300, 300)
            img.thumbnail(output_size)
            img.save(self.image.path)

    class Meta:
        verbose_name = 'User'
        verbose_name_plural = 'Users'
        ordering = ['-id']

forms.py

class UpdateProfile(BSModalForm):
    birthday = forms.DateField(
        error_messages={'invalid': 'Enter a valid date in YYYY-MM-DD format.'}
    )
    class Meta:
        model = Subscriber
        fields = ['city', 'country', 'birthday', 'image']

views.py

class ProfileUpdateView(BSModalUpdateView):
    model = Subscriber
    template_name = 'users/actions/profile-update.html'
    form_class = UpdateProfile
    success_message = 'Success: Profile was updated.'
    success_url = reverse_lazy('users:profile')

code_from_html.html

<div class = 'mt-5 float-right'>
    <button href="" class = 'update-profile btn btn-primary' data-id="{% url 'users:update-profile' subscriber.pk %}" >Update Profile</button>
</div>

<script type="text/javascript">
    $(function () {

      // Update profile buttons
      $(".update-profile").each(function () {
        $(this).modalForm({formURL: $(this).data('id')});
      });

    });
</script>

CRUD app

Wonderfull, Amazing job, thank you.

Hi Uroš,

I will do everything to get that CRUD part , when that would be ready ???, do you have an ETA ??

You did and amazing job, by puting a working django project here. I learnt a lot. thank you

I'm on something (2 small function based view) to convert from Function based view to Class Based View, would you like to help with ? pleaassse, I'm stuck

[Deprecation] Synchronous XMLHttpRequest on the main thread

Hi Uroš,

I got a console deprecation warning message :

 [Deprecation] Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check https://xhr.spec.whatwg.org/.      --> jquery-3.2.1.min.js:4

I thought it coming from my other scripts and after google the thing, and learn a bit, it appears it is related to ajax call (wich in my entire project there's just django-bootstrap-modal-form right now that makes a call)

Any Idea ???

Thank you

support for sending files

Hi, I have a question, does the plugin have support for sending files from an inputfile field?
I tried to implement it, but when sending, the field becomes null and throws the exception required field.
Thanks for the help.

DeleteMessageMixin missing ajax check

while renaming DeleteAjaxMixin to DeleteMessageMixin the ajax check was removed:

if not request.is_ajax():

so django try to delete the object two times ...

Why double POST?

Maybe I just don't understand the operation, but using the example code, whenever I create or update a book I see two POSTs being sent to the Django runserver. It didn't seem to cause a problem with the example code. Only one record is created in the example. But as I build custom post methods on my views it is causing me problems. Only one record gets created, but other code I run or call from the post method gets run twice. Is this a bug, or runs as designed? Thanks in advance.

successURL: "/", of the .js file

Hi Uroš,

Thank you for the new release, I know you were pulling off your hear... anyway. Your new release does refresh to the success URL '/' but however it is static inside the Javascript , It should take the successURL of the django create class and redirect to it.

I mean :

$.fn.modalForm = function (options) {
// Default settings
var defaults = {
modalID: "#modal",
modalContent: ".modal-content",
modalForm: ".modal-content form",
formURL: null,
successURL: "/",
errorClass: ".invalid"
};

the successURL :"/",
but I had set a different success_url = reverse_lazy('chauffeur:chauffeur-List') in my django ChauffeurCreateModal(CreateView) but it stills go to '/', can this take affect of the success_url or the Django Create class but not javascript, like a dynamic success_url.

You're close, so close.., any other hack ???

Thank you.

Validation only works on first submission

If the form is invalid (e.g. required field is missing), it will be caught on the first submission. If the form is resubmitted without correct the error, user is redirected to successURL. If the form is corrected and resubmitted, user is redirected to successURL, but the new record is not created.

It appears the action method on the modal form is not set after validation error is detected.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.