Usage
Usage in Custom Form
# File: forms.py
from django_flatpickr.widgets import DatePickerInput, TimePickerInput, DateTimePickerInput
from .models import Event
from django import forms
class ToDoForm(forms.Form):
todo = forms.CharField(widget=forms.TextInput())
date = forms.DateField(widget=DatePickerInput())
time = forms.TimeField(widget=TimePickerInput())
datetime = forms.DateTimeField(widget=DateTimePickerInput())
# File: views.py
class CustomFormView(generic.FormView):
template_name = "myapp/custom-form.html"
form_class = ToDoForm
See forms.py, views.py for more details.
Usage in Model Form
# File: forms.py
from django_flatpickr.widgets import DatePickerInput, TimePickerInput, DateTimePickerInput
from .models import Event
from django import forms
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ["name", "start_date", "start_time", "start_datetime"]
widgets = {
"start_date": DatePickerInput(),
"start_time": TimePickerInput(),
"start_datetime": DateTimePickerInput(),
}
# File: views.py
class UpdateView(generic.edit.UpdateView):
model = Event
form_class = EventForm
Usage in Generic View (without a Model Form)
Override get_form_class() with modelform_factory to attach the widgets without declaring a dedicated
ModelForm class.
# File: views.py
from django.forms.models import modelform_factory
from django_flatpickr.widgets import DatePickerInput, TimePickerInput, DateTimePickerInput
class CreateView(generic.edit.CreateView):
model = Event
fields = ["start_date", "start_time", "start_datetime"]
def get_form_class(self):
return modelform_factory(
self.model,
fields=self.fields,
widgets={
"start_date": DatePickerInput(),
"start_time": TimePickerInput(),
"start_datetime": DateTimePickerInput(),
},
)
See views.py CreateView for
the full working example.
Types of DatePickers
DatePickerInput— Date-Picker Calendar.TimePickerInput— Time-Picker Calendar.DateTimePickerInput— DateTime-Picker Calendar.
Implement date-range-picker
DatePickers can be linked together to select a date-range, time-range or date-time-range without writing a single line of JavaScript.
# File: forms.py
from django_flatpickr.widgets import DatePickerInput, TimePickerInput
from django import forms
class EventForm(forms.ModelForm):
class Meta:
model = Event
fields = ["name", "start_date", "end_date", "start_time", "end_time"]
widgets = {
"start_date": DatePickerInput(),
"end_date": DatePickerInput(range_from="start_date"),
"start_time": TimePickerInput(),
"end_time": TimePickerInput(range_from="start_time"),
}
Important
The field referenced by range_from must be rendered before the field that links to it in the
template/HTML output. Inputs are wired up in document order on page load, so if the linked field
appears earlier than its range_from target, the browser console will show
range_from "..." is not a flatpickr input. See Troubleshooting for details.
Quirks
django-filter: range_from uses the FilterSet field name
When using DatePickerInput inside a django-filters FilterSet, pass the FilterSet field name to
range_from — not the underlying model field name.
from django_filters import DateFilter, FilterSet
from django_flatpickr.widgets import DatePickerInput
class EventFilter(FilterSet):
start_date__gt = DateFilter(
field_name="start_date",
lookup_expr="gt",
widget=DatePickerInput(),
)
start_date__lt = DateFilter(
field_name="start_date",
lookup_expr="lt",
widget=DatePickerInput(range_from="start_date__gt"), # FilterSet field name, not model field name
)
See the full working example in the demo app (EventFilter).
django-crispy-forms
Both rendering styles work with {{ form.media }} already on the page:
{% load crispy_forms_tags %}
{{ form.media }}
<!-- Using {% crispy form %} -->
<form method="post">
{% csrf_token %}
{% crispy form %}
</form>
<!-- Using the |crispy filter -->
<form method="post">
{% csrf_token %}
{{ form | crispy }}
</form>
See the crispy-form.html demo template.
Dynamic formsets
Combine with elo80ka/django-dynamic-formset to let users add/remove rows on the client; newly added rows are automatically picked up (see Getting Started → Dynamically added forms).
{{ formset.media }}
<form method="post">
{% csrf_token %}
{{ formset.management_form }}
{% for form in formset %}
<div class="formset">{{ form }}</div>
{% endfor %}
</form>
<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/elo80ka/django-dynamic-formset@v1.2.2/src/jquery.formset.js"></script>
<script>
$(".formset").formset();
</script>
See the custom-formset.html demo template.