29

I am trying to add a calendar date input to one of my forms. There is a wonderful calendar widget that Django uses on its admin pages, but I can't figure out how to add it to a custom form.

I found a couple other questions about the same subject here, but they all seemed to be out of date, complicated, and not working.

Is there a way to include Django's built in calendar widget into one of my forms?

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
MrGlass
  • 9,094
  • 17
  • 64
  • 89
  • 1
    The simplest and quickest way I found so far is using [forms.widgets.DateInput](http://stackoverflow.com/a/38804177/888367) – Andrés Meza-Escallón Sep 07 '16 at 16:28
  • See [this answer](http://stackoverflow.com/a/32544473/5802289) below, it is the most updated one and it is totally straightforward. However, note that this provides 3 drop-down menus (year, month, day) instead of just a calendar box...which IMO is a bit annoying. – J0ANMM Dec 01 '16 at 12:09
  • I manage to get it working on Django 2.0.2. Refer to my Answer on this link. [Django 2 AdminDateWidget](https://stackoverflow.com/questions/12449603/integrate-calendar-widget-in-django-app/49083226#49083226) – Newton M Mar 03 '18 at 10:43

7 Answers7

28

Instead of the Admin widget, consider using the normal "SelectDateWidget" built into Django: https://docs.djangoproject.com/en/stable/ref/forms/widgets/#selectdatewidget

Roman
  • 8,826
  • 10
  • 63
  • 103
rogueleaderr
  • 4,671
  • 2
  • 33
  • 40
  • 3
    This is the better modern way to do this. The other answers are too old now. – Escher Mar 21 '16 at 16:14
  • 4
    Perfect! Then the only thing needed is writing in the Form class definition: `Date = forms.DateField(widget = forms.SelectDateWidget)` – J0ANMM Dec 01 '16 at 12:06
  • 2
    add-on that is useful, to select the range of years that people can chose from (example from 2017 to 2020): widget = SelectDateWidget(years=range(2017, 2020)) – S_alj Jul 17 '17 at 20:33
  • Pro - incredibly easy. Cons - incredibly ugly. Doesn't convey the day of the month at all. Why on earth does Django ship with a viable calendar widget that is so incredibly difficult to integrate into your app? – ArtOfWarfare Jan 21 '21 at 03:22
12

All widgets used by django-admin are in the django/contrib/admin/widgets.py file. Just use that as a usual widget in a form. What you want is AdminDateWidget.

from django.contrib.admin.widgets import AdminDateWidget
from django.forms.fields import DateField

class MyForm(Form):
    my_field = DateField(widget=AdminDateWidget)

That will create a date-picker with calendar. You may try to customize it to what you need by extending it or create a new widget from a scratch with an inspiration from AdminDateWidget.

nael
  • 1,441
  • 19
  • 36
davekr
  • 2,266
  • 1
  • 26
  • 32
  • 2
    when I try the code above, I get an error that `DateField` is not defined. I also tried `forms.DateField`, but then I just end up with a txt field. – MrGlass Mar 28 '11 at 04:27
  • It seems that my template isn't outputting the required JS files at the top. Is there another tag needed for my template to include those? – MrGlass Mar 28 '11 at 05:07
  • 1
    You should import DateField `from django.forms.fields import DateField` I am sure you figured it out. And yeah there's a tag which you have to use in template `{% load i18n %}` for javascript to load. I used base.html template from admin, so I didn't have to import all needed files. – davekr Mar 29 '11 at 19:15
10

I figured it out, thanks to Dave S. and a number of old posts on this topic. My successful method:

Create a custom form.

At the top, import the admin widgets using from django.contrib.admin.widgets import AdminDateWidget. Then, add the different fields of your form, using my_field = DateField(widget = AdminDateWidget) whenever you want to use the date widget.

Create your form template

Place the following toward the top to include the appropriate css/js files:

{% load i18n admin_modify adminmedia %}
{% block extrahead %}{{ block.super }}
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/base.css" />
<link rel="stylesheet" type="text/css" href="{% admin_media_prefix %}css/widgets.css" />
<script type="text/javascript" src="/jsi18n/"></script>
<script type="text/javascript" src="{% admin_media_prefix %}js/core.js"></script>
{{ form.media }}
{% endblock %}

Note: You do not necessarily need all of this, depending upon your version of Django and how you are implementing the form fields. this is what I found that I needed to use the widgets.

Now just output your form like normal, and the JS should automatically convert it to a date field. Enjoy!

MrGlass
  • 9,094
  • 17
  • 64
  • 89
  • 1
    If jsi18n lives somewhere else, here is the way to go: {% url 'admin:jsi18n' as jsi18nurl %} (For older Django versions you might also want {% load url from future %}) – Vajk Hermecz Aug 14 '14 at 22:56
  • For this to fully work as in the admin you should also add these js files to your header alongside the core.js – serguitus Aug 12 '19 at 03:32
5

You can do this by form widget " SelectDateWidget()" like this example:

class MyForm(forms.Form):

        start_date=forms.DateField(widget = forms.SelectDateWidget())
        end_date=forms.DateField(widget = forms.SelectDateWidget())
Projesh Bhoumik
  • 1,058
  • 14
  • 17
1

use django form widget called NumberInput as the widget for any datefield or datetimefield in Django This will render the basic HTML NumberInput field for the user to select. I just tested this and it works when the backend recieves the date if you treat it like a python datetime object

from django.forms.widgets import NumberInput

# label and required are both optional arguments  
date_input = forms.DateTimeField(label="Date", required=True, widget=NumberInput(attrs={'type':'date'}))
0

This is basically a duplicate of Using Django time/date widgets in custom form.

The answer has been given by @Dave S and @MrGlass, but for Django 1.2 and later this will additionally also be needed to help the JavaScript find the admin media:

{% load adminmedia %} /* At the top of the template. */

/* In the head section of the template. */
<script type="text/javascript">
window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";
</script>

(from Carl Meyer's answer)

Community
  • 1
  • 1
Herman Schaaf
  • 46,821
  • 21
  • 100
  • 139
0

If anyone would be still looking for a neat solution then here's what I found in the internet:

write in file 'forms.py':

from django.forms import DateInput

class DateInput(DateInput):
    input_type = 'date'

class DateForm(Form):
    date = DateField(widget=DateInput)

then simply use the form in your 'views.py':

date = DateForm()

You will get such view: date widget

PLR06157
  • 3
  • 3