DjangoでDatepicker(カレンダーによる日時入力)を使用する方法

Datepickerとは?

Datepickerはカレンダー選択による日時入力インターフェースです。
日時入力フィールドにフォーカスを与えるとカレンダーがポップアップ表示され、カレンダーで年月日時間を選択することで指定の値を入力することが出来ます。

django-bootstrap-datepicker-plus

ここではDjango用Datepickerのライブラリである「django-bootstrap-datepicker-plus」をご紹介します。

条件

  • Django 2.1.3
  • Python 3.7.0

DjangoでのDatepickerの使い方

PyCharmでdjango-bootstrap-datepicker-plusを使用するチュートリアルの手順をご紹介します。

以下のサイトを参考にしています。
https://django-bootstrap-datepicker-plus.readthedocs.io/en/latest/Walkthrough.html

プロジェクトのチェックアウト

バージョン管理からのチェックアウト > Gitで以下のURLを指定しプロジェクトをクローンします。
https://github.com/monim67/django-polls

以下のように「django-polls」プロジェクトがクローンされます。

必要パッケージのインストール

  • django-bootstrap4
  • django-bootstrap-datepicker-plus

メニューのファイル > 設定 > プロジェクト:django-polls > プロジェクト・インタープリターを選択します。

右上「最新バージョン」横の+ボタンを押します。
使用可能なパッケージ画面が開くので検索入力欄に「django-bootstrap4」を入力します。

「django-bootstrap4」が選択された状態でパッケージのインストールボタンを押してインストールします。
同様に「django-bootstrap-datepicker-plus」もインストールします。

使用可能なパッケージ画面を閉じると、パッケージ一覧に「django-bootstrap4」「django-bootstrap-datepicker-plus」が追加されていることがわかります。

OKボタンを押して設定画面を閉じます。

INSTALLED_APPSへの追記

mysite/settings.pyのINSTALLED_APPSに以下の2行を追記します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
"bootstrap4",
"bootstrap_datepicker_plus",
"bootstrap4", "bootstrap_datepicker_plus",
"bootstrap4",
"bootstrap_datepicker_plus",

CreateViewの追加

polls/views.pyにCreateViewを追記します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# FIle: polls/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from bootstrap_datepicker_plus import DateTimePickerInput
from .models import Choice, Question
class CreateView(generic.edit.CreateView):
model = Question
fields = ['question_text', 'pub_date']
def get_form(self):
form = super().get_form()
form.fields['pub_date'].widget = DateTimePickerInput()
return form
# 他のクラスは変更なし
# FIle: polls/views.py from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404, render from django.urls import reverse from django.views import generic from bootstrap_datepicker_plus import DateTimePickerInput from .models import Choice, Question class CreateView(generic.edit.CreateView): model = Question fields = ['question_text', 'pub_date'] def get_form(self): form = super().get_form() form.fields['pub_date'].widget = DateTimePickerInput() return form # 他のクラスは変更なし
# FIle: polls/views.py
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic

from bootstrap_datepicker_plus import DateTimePickerInput

from .models import Choice, Question


class CreateView(generic.edit.CreateView):
    model = Question
    fields = ['question_text', 'pub_date']
    def get_form(self):
        form = super().get_form()
        form.fields['pub_date'].widget = DateTimePickerInput()
        return form

# 他のクラスは変更なし

テンプレートファイルの追加

polls/templates/polls/question_form.htmlを追加します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!-- File: polls/templates/polls/question_form.html -->
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
<form method="post">{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Save">
</form>
<!-- File: polls/templates/polls/question_form.html --> {% load bootstrap4 %} {% bootstrap_css %} {% bootstrap_javascript jquery='full' %} {{ form.media }} <form method="post">{% csrf_token %} {% bootstrap_form form %} <input type="submit" value="Save"> </form>
<!-- File: polls/templates/polls/question_form.html -->
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}

<form method="post">{% csrf_token %}
  {% bootstrap_form form %}
  <input type="submit" value="Save">
</form>

モデルにget_absolute_urlを追加

polls/models.pyのQuestionモデルにget_absolute_urlメソッドを追加します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# FIle: polls/models.py
import datetime
from django.db import models
from django.urls import reverse
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
def get_absolute_url(self):
return reverse('polls:detail', kwargs={'pk': self.pk})
# FIle: polls/models.py import datetime from django.db import models from django.urls import reverse from django.utils import timezone class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField('date published') def __str__(self): return self.question_text def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1) def get_absolute_url(self): return reverse('polls:detail', kwargs={'pk': self.pk})
# FIle: polls/models.py
import datetime

from django.db import models
from django.urls import reverse
from django.utils import timezone


class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    def get_absolute_url(self):
        return reverse('polls:detail', kwargs={'pk': self.pk})

URLパターンの追加

polls/urls.pyのURLパターンにcreateを追加します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# FIle: polls/urls.py
from django.urls import path
from . import views
app_name = 'polls'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('create', views.CreateView.as_view(), name='create'),
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
path('<int:question_id>/vote/', views.vote, name='vote'),
]
# FIle: polls/urls.py from django.urls import path from . import views app_name = 'polls' urlpatterns = [ path('', views.IndexView.as_view(), name='index'), path('create', views.CreateView.as_view(), name='create'), path('<int:pk>/', views.DetailView.as_view(), name='detail'), path('<int:pk>/results/', views.ResultsView.as_view(), name='results'), path('<int:question_id>/vote/', views.vote, name='vote'), ]
# FIle: polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('create', views.CreateView.as_view(), name='create'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
    path('<int:question_id>/vote/', views.vote, name='vote'),
]

実行

Ctrl + Alt + Rを押してPyCharmのmanage.pyコンソールを開きます。
「runserver」を入力してEnterを押します。

ブラウザで以下のURLを開きます。
http://localhost:8000/polls/create

「Date published」の入力欄または右側のカレンダーアイコンをクリックするとカレンダーがポップアップ表示します。

カレンダーを閉じると選択した日時が入力された状態になります。

以上で完了です。

日時のフォーマット指定

以下のように、パラメータでformatを指定することで日時の表示を変えることが出来ます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class CreateView(generic.edit.CreateView):
model = Question
fields = ['question_text', 'pub_date']
def get_form(self):
form = super().get_form()
form.fields['pub_date'].widget = DateTimePickerInput(format='%Y-%m-%d')
return form
class CreateView(generic.edit.CreateView): model = Question fields = ['question_text', 'pub_date'] def get_form(self): form = super().get_form() form.fields['pub_date'].widget = DateTimePickerInput(format='%Y-%m-%d') return form
class CreateView(generic.edit.CreateView):
    model = Question
    fields = ['question_text', 'pub_date']
    def get_form(self):
        form = super().get_form()
        form.fields['pub_date'].widget = DateTimePickerInput(format='%Y-%m-%d')
        return form

NGケース(解決方法あり)

原因は不明ですが、「format=’%Y/%m/%d’」とすると、日時のフォーマットチェックに必ず引っかかってしまうようです。

原因

Djangoの日時チェックで使用される「DATETIME_INPUT_FORMATS」に「’%Y/%m/%d’」が無いのが原因です。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
DATETIME_INPUT_FORMATS = [
'%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
'%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200'
'%Y-%m-%d %H:%M', # '2006-10-25 14:30'
'%Y-%m-%d', # '2006-10-25'
'%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59'
'%m/%d/%Y %H:%M:%S.%f', # '10/25/2006 14:30:59.000200'
'%m/%d/%Y %H:%M', # '10/25/2006 14:30'
'%m/%d/%Y', # '10/25/2006'
'%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59'
'%m/%d/%y %H:%M:%S.%f', # '10/25/06 14:30:59.000200'
'%m/%d/%y %H:%M', # '10/25/06 14:30'
'%m/%d/%y', # '10/25/06'
]
DATETIME_INPUT_FORMATS = [ '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59' '%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200' '%Y-%m-%d %H:%M', # '2006-10-25 14:30' '%Y-%m-%d', # '2006-10-25' '%m/%d/%Y %H:%M:%S', # '10/25/2006 14:30:59' '%m/%d/%Y %H:%M:%S.%f', # '10/25/2006 14:30:59.000200' '%m/%d/%Y %H:%M', # '10/25/2006 14:30' '%m/%d/%Y', # '10/25/2006' '%m/%d/%y %H:%M:%S', # '10/25/06 14:30:59' '%m/%d/%y %H:%M:%S.%f', # '10/25/06 14:30:59.000200' '%m/%d/%y %H:%M', # '10/25/06 14:30' '%m/%d/%y', # '10/25/06' ]
DATETIME_INPUT_FORMATS = [
    '%Y-%m-%d %H:%M:%S',     # '2006-10-25 14:30:59'
    '%Y-%m-%d %H:%M:%S.%f',  # '2006-10-25 14:30:59.000200'
    '%Y-%m-%d %H:%M',        # '2006-10-25 14:30'
    '%Y-%m-%d',              # '2006-10-25'
    '%m/%d/%Y %H:%M:%S',     # '10/25/2006 14:30:59'
    '%m/%d/%Y %H:%M:%S.%f',  # '10/25/2006 14:30:59.000200'
    '%m/%d/%Y %H:%M',        # '10/25/2006 14:30'
    '%m/%d/%Y',              # '10/25/2006'
    '%m/%d/%y %H:%M:%S',     # '10/25/06 14:30:59'
    '%m/%d/%y %H:%M:%S.%f',  # '10/25/06 14:30:59.000200'
    '%m/%d/%y %H:%M',        # '10/25/06 14:30'
    '%m/%d/%y',              # '10/25/06'
]
対応

settings.pyに以下を記述することで、日時チェックを通すことが出来ます。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
USE_L10N = False # DATETIME_INPUT_FORMATSに変更を加えるため、Falseに設定
from django.conf.global_settings import DATETIME_INPUT_FORMATS
DATETIME_INPUT_FORMATS += ('%Y/%m/%d',)
USE_L10N = False # DATETIME_INPUT_FORMATSに変更を加えるため、Falseに設定 from django.conf.global_settings import DATETIME_INPUT_FORMATS DATETIME_INPUT_FORMATS += ('%Y/%m/%d',)
USE_L10N = False  # DATETIME_INPUT_FORMATSに変更を加えるため、Falseに設定

from django.conf.global_settings import DATETIME_INPUT_FORMATS

DATETIME_INPUT_FORMATS += ('%Y/%m/%d',)

settings.pyを以下のように記述しても、日時チェックが通るようです。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
LANGUAGE_CODE = 'ja-jp'
TIME_ZONE = 'Asia/Tokyo'
USE_I18N = True
USE_L10N = True
USE_TZ = False
from django.conf.global_settings import DATETIME_INPUT_FORMATS
DATETIME_INPUT_FORMATS += ('%Y/%m/%d',)
LANGUAGE_CODE = 'ja-jp' TIME_ZONE = 'Asia/Tokyo' USE_I18N = True USE_L10N = True USE_TZ = False from django.conf.global_settings import DATETIME_INPUT_FORMATS DATETIME_INPUT_FORMATS += ('%Y/%m/%d',)
LANGUAGE_CODE = 'ja-jp'

TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = False

from django.conf.global_settings import DATETIME_INPUT_FORMATS

DATETIME_INPUT_FORMATS += ('%Y/%m/%d',)

カスタムフォームで使用する

カスタムフォームで「django-bootstrap-datepicker-plus」を使用する方法をご紹介します。

カスタムフォーム追加

polls/forms.pyを追加します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# File: forms.py
from bootstrap_datepicker_plus import DatePickerInput
from django import forms
class ToDoForm(forms.Form):
todo = forms.CharField(
widget=forms.TextInput(attrs={"class": "form-control"})
)
date = forms.DateField(
widget=DatePickerInput(format='%m/%d/%Y')
)
# File: forms.py from bootstrap_datepicker_plus import DatePickerInput from django import forms class ToDoForm(forms.Form): todo = forms.CharField( widget=forms.TextInput(attrs={"class": "form-control"}) ) date = forms.DateField( widget=DatePickerInput(format='%m/%d/%Y') )
# File: forms.py
from bootstrap_datepicker_plus import DatePickerInput
from django import forms

class ToDoForm(forms.Form):
    todo = forms.CharField(
        widget=forms.TextInput(attrs={"class": "form-control"})
    )
    date = forms.DateField(
        widget=DatePickerInput(format='%m/%d/%Y')
    )

viewsの編集

polls/viewsのCreatViewにget_context_dataを追加してToDoFormをcontextに渡すようにします。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
from .forms import ToDoForm
class CreateView(generic.edit.CreateView):
model = Question
fields = ['question_text', 'pub_date']
def get_form(self):
form = super().get_form()
form.fields['pub_date'].widget = DateTimePickerInput()
return form
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
form = ToDoForm()
context['todo_form'] = form
return context
from .forms import ToDoForm class CreateView(generic.edit.CreateView): model = Question fields = ['question_text', 'pub_date'] def get_form(self): form = super().get_form() form.fields['pub_date'].widget = DateTimePickerInput() return form def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) form = ToDoForm() context['todo_form'] = form return context
from .forms import ToDoForm


class CreateView(generic.edit.CreateView):
    model = Question
    fields = ['question_text', 'pub_date']
    def get_form(self):
        form = super().get_form()
        form.fields['pub_date'].widget = DateTimePickerInput()
        return form

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        form = ToDoForm()
        context['todo_form'] = form
        return context

テンプレートの編集

polls/templates/polls/question_form.htmlに{{ todo_form }}を追記します。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<!-- File: polls/templates/polls/question_form.html -->
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}
<form method="post">{% csrf_token %}
{% bootstrap_form form %}
<input type="submit" value="Save">
</form>
{{ todo_form }}
<!-- File: polls/templates/polls/question_form.html --> {% load bootstrap4 %} {% bootstrap_css %} {% bootstrap_javascript jquery='full' %} {{ form.media }} <form method="post">{% csrf_token %} {% bootstrap_form form %} <input type="submit" value="Save"> </form> {{ todo_form }}
<!-- File: polls/templates/polls/question_form.html -->
{% load bootstrap4 %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
{{ form.media }}

<form method="post">{% csrf_token %}
  {% bootstrap_form form %}
  <input type="submit" value="Save">
</form>

{{ todo_form }}

サーバー実行

「runserver」を実行し、ブラウザで以下のURLを開きます。
http://localhost:8000/polls/create

追加したToDoフォームが追加されていることがわかります。

フォームの設定例

フォームでオプションを指定することにより様々な設定を行うことが出来ます。

以下は、開始日時と終了日時で日時にの大小に齟齬が出ないようにした一例です。

「.start_of(‘term’)および.end_of(‘term’)」でペアを指定しています。
また、初期表示や表示フォーマット、最小/最大日時の設定なども行っています。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
class SampleForm(forms.Form):
start_date = forms.DateField(
label='開始日時',
widget=datetimepicker.DateTimePickerInput(
format='%Y/%m/%d %H:%M:%S',
options={
'locale': 'ja',
'dayViewHeaderFormat': 'YYYY年 MMMM',
'ignoreReadonly': True,
'allowInputToggle': True,
'minDate': '2018/10/22', # 最小日時(データ取得開始日)
'defaultDate': '2018/10/22', # 初期表示
}
).start_of('term'),
)
end_date = forms.DateField(
label='終了日時',
initial=dt.now().strftime('%Y/%m/%d %H:%M:%S'), # 初期値
widget=datetimepicker.DateTimePickerInput(
format='%Y/%m/%d %H:%M:%S',
options={
'locale': 'ja',
'dayViewHeaderFormat': 'YYYY年 MMMM',
'ignoreReadonly': True,
'allowInputToggle': True,
'maxDate': (dt.now() + timedelta(days = 1)).strftime('%Y/%m/%d %H:%M:%S'), # 最大日時(翌日)
}
).end_of('term'),
)
class SampleForm(forms.Form): start_date = forms.DateField( label='開始日時', widget=datetimepicker.DateTimePickerInput( format='%Y/%m/%d %H:%M:%S', options={ 'locale': 'ja', 'dayViewHeaderFormat': 'YYYY年 MMMM', 'ignoreReadonly': True, 'allowInputToggle': True, 'minDate': '2018/10/22', # 最小日時(データ取得開始日) 'defaultDate': '2018/10/22', # 初期表示 } ).start_of('term'), ) end_date = forms.DateField( label='終了日時', initial=dt.now().strftime('%Y/%m/%d %H:%M:%S'), # 初期値 widget=datetimepicker.DateTimePickerInput( format='%Y/%m/%d %H:%M:%S', options={ 'locale': 'ja', 'dayViewHeaderFormat': 'YYYY年 MMMM', 'ignoreReadonly': True, 'allowInputToggle': True, 'maxDate': (dt.now() + timedelta(days = 1)).strftime('%Y/%m/%d %H:%M:%S'), # 最大日時(翌日) } ).end_of('term'), )
class SampleForm(forms.Form):

    start_date = forms.DateField(
        label='開始日時',
        widget=datetimepicker.DateTimePickerInput(
            format='%Y/%m/%d %H:%M:%S',
            options={
                'locale': 'ja',
                'dayViewHeaderFormat': 'YYYY年 MMMM',
                'ignoreReadonly': True,
                'allowInputToggle': True,
                'minDate': '2018/10/22', # 最小日時(データ取得開始日)
                'defaultDate': '2018/10/22', # 初期表示
            }
        ).start_of('term'),
    )
    end_date = forms.DateField(
        label='終了日時',
        initial=dt.now().strftime('%Y/%m/%d %H:%M:%S'),  # 初期値
        widget=datetimepicker.DateTimePickerInput(
            format='%Y/%m/%d %H:%M:%S',
            options={
                'locale': 'ja',
                'dayViewHeaderFormat': 'YYYY年 MMMM',
                'ignoreReadonly': True,
                'allowInputToggle': True,
                'maxDate': (dt.now() + timedelta(days = 1)).strftime('%Y/%m/%d %H:%M:%S'),  # 最大日時(翌日)
            }
        ).end_of('term'),
    )

詳細は以下を参照してください。
http://eonasdan.github.io/bootstrap-datetimepicker/Options/

参考

django-bootstrap-datepicker-plus documentation

https://django-bootstrap-datepicker-plus.readthedocs.io/en/latest/index.html

DjangoでDatepicker(カレンダーによる日時入力)を使用する方法” に対して1件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です