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:
- Install Django Bootstrap Datepicker using pip install django-bootstrap-datepicker-plus and follow the package installation instructions
- 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 formsfrom bootstrap_datepicker_plus import DatePickerInputEVENT_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")
-
- 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}
- 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",],},},]
-
- 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}}
- Write your function based view
-
from django.http import JsonResponsefrom django.template.loader import render_to_stringdef 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"] = Falseelse:quote_form = RequestQuoteForm()data["html_form"] = render_to_string("pages/includes/partial_quote_form.html",{"quote_form": quote_form},request=request,)return JsonResponse(data)
-
- 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);
});
-
- 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>
-
- 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>
-
- 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>
-
- 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>
-