Django Bootstrap Datepicker In Modal Tutorial

Rendering a Bootstrap Datepicker inside a modal using the bootstrap-datepicker-plus package for Django can sometimes cause some issues based on the order your page loads your scripts. Using a context processor that gives every template access to the form’s media should solve the issue.

I am using Django 3.1 and using Javascript and Ajax to load and submit the form. Here is a quick tutorial:

1. Install Django Bootstrap Datepicker using pip install django-bootstrap-datepicker-plus and follow the package installation instructions

2. Create your form and load the DatePicker widget. In this example I am using a generic Django Form. If you’re using a Model Form, follow the instructions from the package installation link above

from django import forms
from bootstrap_datepicker_plus import DatePickerInput
 
EVENT_TYPE_CHOICES = [
     ("Wedding", "Wedding"),
     ("Bar/Bat Mitzvah", "Bar/Bat Mitzvah"),
     ("Corporate", "Corporate"),
     ("Private Party", "Private Party"),
]
 
class RequestQuoteForm(forms.Form):
       name = name = forms.CharField(max_length=100)
       email = forms.EmailField()
       phone = forms.CharField(max_length=15)
       event_date = forms.DateField(widget=DatePickerInput(format="%m/%d/%Y"), label="Event Date")
       event_type = forms.ChoiceField(choices=EVENT_TYPE_CHOICES, label="Event Type")

3. Create a Context Processor

Inside your app directory create a new file called context_processors.py 

from .forms import RequestQuoteForm

def quote_form_processor(request):
     quote_form = RequestQuoteForm()
     return {'quote_form': quote_form}

4. In your settings.py add the context processor to your TEMPLATES

TEMPLATES = [
        {
            "BACKEND": "django.template.backends.django.DjangoTemplates",
            "DIRS": [str(BASE_DIR.joinpath("templates"))],
            "APP_DIRS": True,
            "OPTIONS": {
                   "context_processors": [
                          "django.template.context_processors.debug",
                          "django.template.context_processors.request",
                          "django.contrib.auth.context_processors.auth",
                          "django.contrib.messages.context_processors.messages",
                          "pages.context_processors.quote_form_processor",
                     ],
               },
         },
   ]

5. Load the media in your base.html template. NOTE: Make sure the form name matches the name you set in your context processor.

{{quote_form.media}}

6. Write your function based view

from django.http import JsonResponse
from django.template.loader import render_to_string
 
def request_quote(request):
    data = dict()
    if request.method == "POST":
         form = RequestQuoteForm(request.POST or None)
         if form.is_valid():
 
             data["html_success_message"] = render_to_string(
                   "pages/includes/partial_quote_submit_success.html", request=request,
              )
             data["form_is_valid"] = True

        else:
             data["form_is_valid"] = False
    else:
         quote_form = RequestQuoteForm()
         data["html_form"] = render_to_string(
               "pages/includes/partial_quote_form.html",
                {"quote_form": quote_form},
                request=request,
                )
return JsonResponse(data)

7. In your static folder create a file named custom.js and load file in the footer of your base.html template

$(function () {

      /* Functions */

      var loadForm = function () {
         var btn = $(this);
         $.ajax({
            url: btn.attr("data-url"),
            type: 'get',
            dataType: 'json',
            beforeSend: function () {
               $("#modal-base .modal-content").html("");
               $("#modal-base").modal("show");
             },
          success:function (data) {
              $("#modal-base .modal-content").html(data.html_form);
          }
      });
   };

var saveForm = function () {
     var form = $(this);
     $.ajax({
         url: form.attr("action"),
         data: form.serialize(),
         type: form.attr("method"),
         dataType: 'json',
         success: function (data) {
            if (data.form_is_valid) {
                $("#modal-base .modal-content").html(data.html_success_message);
            }
            else {
               $("#modal-base .modal-content").html(data.html_form);
            }
       }
    });
    returnfalse;
};


   /* Binding */


   // Request Quote
   $(".js-quote-request").on("click", loadForm);
   $("#modal-base").on("submit", ".js-quote-request-form", saveForm);

});

8. Create your form template and load the form media again

{{quote_form.media}}
<form method="POST" action="{% url 'request_quote' %}" class="js-quote-request-form" id="quoteForm">
     {% csrf_token %}
     <div class="modal-header">
         <h4 class="modal-title">Request a Quote</h4>
      </div>
      <div class="modal-body">
          {% bootstrap_form_errors quote_form %}
          {% bootstrap_form quote_form %}

      </div>
      <div class="modal-footer">
          <button type="button"class="btn btn-default" data-dismiss="modal">Close</button>
          {% bootstrap_button "Schedule" button_type="submit" button_class="btn-primary"%}
     </div>
</form>

9. Create your success template

<div class="modal-header">
      <h4 class="modal-title">Quote Request Sent</h4>
</div>
<div class="modal-body">
        Thank you for submitting your form! We will be in touch soon!

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

10. Add the modal to your base.html template

<div class="modal fade" id="modal-base">
   <div class="modal-dialog modal-dialog-centered">
       <div class="modal-content">
       </div>
    </div>
</div>

11. Render your modal from any template using a button

<button data-url="{% url 'request_quote' %}" class="btn btn-lg btn-primary js-quote-request">Request a Quote</button>
SHARE

FREE SEO AUDIT REPORT

Find opportunities to improve your page's rank for a target keyword

Detailed report emailed as a PDF

Actionable suggested improvements

Leave a Comment

Send Us A Message

Schedule Your FREE Digital Marketing Strategy Call

What Happens
On A Strategy Call?