# django-flatpickr Documentation # Home ## Home # django-flatpickr This django widget contains Date-Picker, Time-Picker, DateTime-Picker input widgets with date-range-picker functionality for django version \>= 2.0. The widget implements [flatpickr](https://github.com/flatpickr/flatpickr) to display date-pickers in django model forms and custom forms which can be configured easily for date-range selection. For Bootstrap date-picker see [django-bootstrap-datepicker-plus](https://github.com/monim67/django-bootstrap-datepicker-plus). [![Build Status][ci-status]][ci-status-target] [![Coverage Status][coverage]][coverage-target] [![Python Versions][pyversions]][pyversions-target] [![DJango Versions][djversions]][djversions-target] ![Flatpickr Red Theme][flatpickr-red-theme] ![Flatpickr Default Theme][flatpickr-default-theme] ![Flatpickr Dark Theme][flatpickr-dark-theme] ## Demo - [Custom Form][demo_custom_form]. - [Model Form][demo_model_form]. - [Generic View (without Model Form)][demo_generic_view]. - [With django-crispy-forms][demo_crispy_form]. - [With django-filter][demo_django_filter]. - [With dynamic formsets][demo_dynamic_formset]. - [In a Modal][demo_modal_form]. ## Where to Start - Follow the [Getting Started documentation][doc_getting_started]. - Pass [llms.txt](https://monim67.github.io/django-flatpickr/llms.txt)/[llms-full.txt](https://monim67.github.io/django-flatpickr/llms-full.txt) to your coding agent. ## Contributing - [CONTRIBUTING.md](https://github.com/monim67/django-flatpickr/blob/master/.github/CONTRIBUTING.md). - [CODE_OF_CONDUCT.md](https://github.com/monim67/django-flatpickr/blob/master/.github/CODE_OF_CONDUCT.md). ## License This project is licensed under the [MIT LICENSE](https://github.com/monim67/django-flatpickr/blob/master/LICENSE). [ci-status]: https://github.com/monim67/django-flatpickr/actions/workflows/build.yml/badge.svg?event=push [ci-status-target]: https://github.com/monim67/django-flatpickr/actions/workflows/build.yml [coverage]: https://coveralls.io/repos/github/monim67/django-flatpickr/badge.svg?branch=master [coverage-target]: https://coveralls.io/github/monim67/django-flatpickr?branch=master [demo_crispy_form]: https://monim67.github.io/django-flatpickr/demo/crispy-form.html [demo_custom_form]: https://monim67.github.io/django-flatpickr/demo/custom-form.html [demo_django_filter]: https://monim67.github.io/django-flatpickr/demo/django-filter.html [demo_dynamic_formset]: https://monim67.github.io/django-flatpickr/demo/dynamic-formset.html [demo_generic_view]: https://monim67.github.io/django-flatpickr/demo/generic-view.html [demo_modal_form]: https://monim67.github.io/django-flatpickr/demo/modal-window.html [demo_model_form]: https://monim67.github.io/django-flatpickr/demo/generic-view-with-model-form-1.html [djversions]: https://img.shields.io/pypi/djversions/django-flatpickr.svg [djversions-target]: https://pypi.python.org/pypi/django-flatpickr [doc_getting_started]: https://monim67.github.io/django-flatpickr/getting-started/ [flatpickr-dark-theme]: https://cloud.githubusercontent.com/assets/11352152/14549372/3cbc8514-028d-11e6-8daf-ec1ba01c9d7e.PNG [flatpickr-default-theme]: https://cloud.githubusercontent.com/assets/11352152/14549370/3cadb750-028d-11e6-818d-c6a1bc6349fc.PNG [flatpickr-red-theme]: https://cloud.githubusercontent.com/assets/11352152/14549374/3cc01102-028d-11e6-9ff4-0cf208a310c4.PNG [pyversions]: https://img.shields.io/pypi/pyversions/django-flatpickr.svg [pyversions-target]: https://pypi.python.org/pypi/django-flatpickr # Getting Started ## Getting Started # Getting Started ## Prerequisites - Python >= 3.10 - Django >= 2.0 ## Install Install the PyPI package via pip. ```bash pip install django-flatpickr ``` Add `django_flatpickr` to the list of `INSTALLED_APPS` in your `settings.py` file. ```python INSTALLED_APPS = [ # Add the following "django_flatpickr", ] ``` ## Configure template The widget requires `{{ form.media }}` in your template to load flatpickr's JS/CSS. The calendar will silently not appear if `{{ form.media }}` is missing. !!! tip For better page performance, use `{{ form.media.css }}` in `
` and `{{ form.media.js }}` just before ``. ```html {{ form.media }} ``` Then head over to the [Usage](usage.md) page to see how to use it in forms and views. ## Quirks ### Formsets: use `formset.media`, not the media of individual forms Django's `BaseFormSet` has its own `.media` property that aggregates widget assets across all its forms. Use it once (outside the loop) rather than emitting media inside the loop for each form. ```html {{ formset.media }} {{ formset.management_form }} {% for form in formset %} {{ form.as_p }} {% endfor %} ``` See the [formset template in the demo app](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/templates/myapp/custom-formset.html). ### Dynamically added forms (modals, AJAX, dynamic formsets) Unlike widgets that require re-initialization after new HTML is injected into the page, django-flatpickr watches the whole document for changes and automatically initializes any flatpickr input that is added to the DOM later — no extra JavaScript call is required on your end. This means forms shown in a modal (rendered up-front and toggled with CSS, or injected later via AJAX), or new rows added by [django-dynamic-formset](https://github.com/elo80ka/django-dynamic-formset), work out of the box as long as `{{ form.media }}` (or `{{ formset.media }}`) has been rendered somewhere on the page at least once. See the [modal demo template](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/templates/myapp/modal-window.html). # Usage ## Usage # Usage ## Usage in Custom Form ```python # 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](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/forms.py), [views.py](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/views.py) for more details. ## Usage in Model Form ```python # 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. ```python # 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](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/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**. ```python # 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](troubleshooting.md) 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. ```python 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](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/forms.py) (`EventFilter`). ### django-crispy-forms Both rendering styles work with `{{ form.media }}` already on the page: ```html {% load crispy_forms_tags %} {{ form.media }} ``` See the [crispy-form.html demo template](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/templates/myapp/crispy-form.html). ### Dynamic formsets Combine with [elo80ka/django-dynamic-formset](https://github.com/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](getting-started.md#dynamically-added-forms-modals-ajax-dynamic-formsets)). ```html {{ formset.media }} ``` See the [custom-formset.html demo template](https://github.com/monim67/django-flatpickr/blob/master/dev/myapp/templates/myapp/custom-formset.html). # Customization ## Customization # Customization ## Customize All Inputs To customize the look and features of the flatpickr widget, copy the agent friendly settings block below to your `settings.py` file and customize it. Settings apply globally to all flatpickr widgets used in your site. ```python DJANGO_FLATPICKR = { # Name of the theme to use # More themes: https://flatpickr.js.org/themes/ "theme_name": "dark", # # Complete URL of theme CSS file # theme_name is ignored if theme_url is provided # "theme_url": "https://..", # # Global HTML attributes for flatpickr element # "attrs": { # "class": "my-input-class", # }, # # Global options for flatpickr # More options: https://flatpickr.js.org/options/ # Some options are managed by this package and are reserved, see below. # "options": { # "locale": "bn", # locale option can be set here only # "altFormat": "m/d/Y H:i", # specify date format on the front-end # }, # # HTML template to render the flatpickr input, see Template Customizing # "template_name": "your-app/custom-flatpickr-input.html", # # Specify CDN roots. Choose where static JS/CSS are served from. # Can be set to localhost (offline setup) or any other preferred CDN. # "flatpickr_cdn_url": "https://cdn.jsdelivr.net/npm/flatpickr@4.6.13/dist/", # "app_static_url": "https://cdn.jsdelivr.net/gh/monim67/django-flatpickr@2.0.0/src/django_flatpickr/static/django_flatpickr/", # # Advanced: To serve static files from Django's staticfiles instead of a CDN # (e.g. for GDPR / offline / compliance requirements), download the JS/CSS # files into a static directory, replace CDN links above with link to projects # static assets, and update app_static_url as below: # "app_static_url": "django_flatpickr/", # Note: you will be responsible for static file deployment in production # including collecting django static files and serving them from your web server. } ``` ## Customize Single Input You should use options in `settings.py` to apply settings to all widget instances. If you need to customize a single widget input, pass `attrs` and `options` directly to the widget instance. ```python from django_flatpickr.schemas import FlatpickrOptions class ToDoForm(forms.Form): todo = forms.CharField(widget=forms.TextInput()) start_date = forms.DateField(widget=DatePickerInput( attrs={"class": "my-custom-class"}, # input element attributes options=FlatpickrOptions(altFormat="m/d/Y"), )) ``` ### Reserved options The following options are managed internally by the widget and will raise `ValueError` if set: | Option | Reason | | ------------ | --------------------------------------------------------------------------------------------------------------------------- | | `mode` | Always set to `static`; range selection is implemented via `range_from` instead. | | `dateFormat` | Always fixed to the format needed to submit values back to Django; use `altFormat` to control the format shown to the user. | | `altInput` | Always `True`. | | `wrap` | Always `True` (required for the input template's toggle/clear buttons). | | `enableTime` | Set automatically based on the widget used (`TimePickerInput`/`DateTimePickerInput`). | | `noCalendar` | Set automatically based on the widget used (`TimePickerInput`). | ## JavaScript-only options and events Some flatpickr options (and all event hooks, e.g. `onChange`) can only be set using JavaScript. Set them globally for all widgets: ```javascript window.djangoFlatpickrOptions = { onChange: function (selectedDates) { console.log(selectedDates) } } ``` Or for a single widget, using the field's name: ```javascript window.djangoFlatpickrOptions_start_date = { onChange: function (selectedDates) { console.log(selectedDates) } } ``` !!! tip The field-specific key is derived from the field's `name` attribute with any formset prefix (e.g. `form-0-`) stripped, so `window.djangoFlatpickrOptions_start_date` applies to a `start_date` field regardless of which formset row it belongs to. ## Localization Use the `locale` option, see [available localization options](https://flatpickr.js.org/localization/). # Template Customizing ## Template Customizing # Template Customizing The calendar itself is not customizable via templates, but the input field's wrapper markup can be. Create an HTML template for the widget input: ```html