Djangoでカレンダーを作るシリーズ
概要
Djangoで、月間カレンダーや週間カレンダー、それぞれにスケジュール表示機能がついたもの、スケジュール登録フォームがついたもの等、様々なカレンダーを作成していきます。
動作環境
Python: 3.6以上
Django: 2.0以上
ソースコードダウンロード
先にソースコードをダウンロードしたい人は、Githubにソースコードがあるのでクローンしてください。
うごかしかた。
git clone https://github.com/naritotakizawa/django-simple-calendar
pip install django (pipenv install でも)
python manage.py migrate
python manage.py runserver
初期設定
アプリケーション名をappとして進めていきます。
python manage.py startapp app
として作成したら、settings.py
にappアプリケーションを定義します。
INSTALLED_APPS = [
'app.apps.AppConfig', # カレンダーアプリ
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
urls.py
にも、appを読み込ませるようにします。この辺はDjangoアプリケーションを作成したら毎回やる操作ですね。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('app.urls')),
]
モデルの作成
スケジュールを管理するモデルとして、models.py
に次のようなモデルを予め定義しておきます。
import datetime
from django.db import models
from django.utils import timezone
class Schedule(models.Model):
"""スケジュール"""
summary = models.CharField('概要', max_length=50)
description = models.TextField('詳細な説明', blank=True)
start_time = models.TimeField('開始時間', default=datetime.time(7, 0, 0))
end_time = models.TimeField('終了時間', default=datetime.time(7, 0, 0))
date = models.DateField('日付')
created_at = models.DateTimeField('作成日', default=timezone.now)
def __str__(self):
return self.summary
概要、説明、スケジュールの開始時間・終了時間・日付、そしてスケジュールの作成日となるフィールドがあります。
ベーステンプレートファイル作成
Bootstrap4のスターターテンプレートを使っていきます。
<!doctype html>
<html lang="ja">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<title>カレンダー</title>
</head>
<body>
<div class="container" mt-3>
{% block content %}{% endblock %}
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js"
integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js"
integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k"
crossorigin="anonymous"></script>
{% block extrajs %}{% endblock %}
</body>
</html>
後で追加のJavaScriptを少し書くので、{% block extrajs %}{% endblock %}
を定義しておきます。
ミックスインクラスの作成
mixins.py
というファイルをappディレクトリ内に作ります。ここに作るクラスは、カレンダー関連ビューを作るための部品です。views.py
に定義しても良いのですが、専用のmixins.py
のようなファイルを作っておくほうが管理しやすいですし、一般的です。
次のようなMixinを定義しておきましょう。これは今後作る各Mixinクラスの、基底クラスになります。
import calendar
from collections import deque
class BaseCalendarMixin:
"""カレンダー関連Mixinの、基底クラス"""
first_weekday = 0 # 0は月曜から、1は火曜から。6なら日曜日からになります。お望みなら、継承したビューで指定してください。
week_names = ['月', '火', '水', '木', '金', '土', '日'] # これは、月曜日から書くことを想定します。['Mon', 'Tue'...
def setup_calendar(self):
"""内部カレンダーの設定処理
calendar.Calendarクラスの機能を利用するため、インスタンス化します。
Calendarクラスのmonthdatescalendarメソッドを利用していますが、デフォルトが月曜日からで、
火曜日から表示したい(first_weekday=1)、といったケースに対応するためのセットアップ処理です。
"""
self._calendar = calendar.Calendar(self.first_weekday)
def get_week_names(self):
"""first_weekday(最初に表示される曜日)にあわせて、week_namesをシフトする"""
week_names = deque(self.week_names)
week_names.rotate(-self.first_weekday) # リスト内の要素を右に1つずつ移動...なんてときは、dequeを使うと中々面白いです
return week_names
内部的に標準ライブラリのcalendar
モジュールを利用してカレンダーを作成しています。
デフォルトでは月曜日からカレンダーが始まりますが、火曜日から表示したいというケースも当然あるので、first_weekday
というクラス属性を定義しています。0はデフォルトの月曜日スタート、1なら火曜日...のようになります。
また、['月', '火', '水'...]
といった曜日のリストを柔軟に取得できるようにget_week_names()
も定義しています。first_weekday
を1にしたならば'['火', '水'...]'といった曜日リストを返してくれますし、week_names
属性を上書きすることで、['Mon', 'Tue']
のように曜日リストの表記も変更できます。
残りのMixinは、後で作っていきます。
月間カレンダー
まず、月間カレンダーを作っていきます。次月、前月といった移動も勿論できます。
週間カレンダー
次は週間カレンダーです。その週ごとに表示するカレンダーですね。こちらも、前週・次週へ移動できます。
スケジュール付き週間カレンダー
上の週間カレンダーに、スケジュールの表示機能をつけたものを作っていきます。
全て1行に収めたり...
縦の表示にしたものなども作っていきます。
スケジュール付き月間カレンダー
今度はスケジュール付きの、月間カレンダーを作ります。
スケジュール付き週間カレンダー+月間カレンダー+スケジュール登録フォーム
スケジュール付き週間カレンダーに月間カレンダーを付け、更にgeneric.CreateViewも使い、スケジュール登録フォームもつけてみます。
一括作成・更新機能付き月間カレンダー
フォームセットを使い、月間カレンダーを表示しつつ、各日のスケジュール登録・更新を一括で行えるようにしていきます。
名無し
このスケジュールモデルだと、
start_time = models.TimeField('開始時間', default=datetime.time(7, 0, 0))において
TypeError: descriptor 'time' requires a 'datetime.datetime' object but received a 'int'
というようなエラーが出てしまいます。 何かコードに誤りがあるのではないでしょうか。
返信する