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行を追記します。

"bootstrap4",
"bootstrap_datepicker_plus",

CreateViewの追加

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

# 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を追加します。

<!-- 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メソッドを追加します。

# 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を追加します。

# 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を指定することで日時の表示を変えることが出来ます。

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’」が無いのが原因です。

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に以下を記述することで、日時チェックを通すことが出来ます。

USE_L10N = False  # DATETIME_INPUT_FORMATSに変更を加えるため、Falseに設定

from django.conf.global_settings import DATETIME_INPUT_FORMATS

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

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

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を追加します。

# 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に渡すようにします。

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 }}を追記します。

<!-- 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’)」でペアを指定しています。
また、初期表示や表示フォーマット、最小/最大日時の設定なども行っています。

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件のコメントがあります。

コメントを残す

メールアドレスが公開されることはありません。