naritoブログ

このブログはPython/DjangoとBootstrap4で作成されました
Githubのソースコード

Djangoで、週間カレンダー

約24日前 2018年5月4日2:35
プログラミング関連
Django Python

概要


Djangoで、カレンダーを作るシリーズの1つです。
週間カレンダーを作成していきます。

以下のようなものが作れます。
週間カレンダー

少し地味に見えるかもしれませんが、月間カレンダーに比べると幅をとらないのが特徴です。なので、その分色々な機能を後で付け足していきます(その日のスケジュール表示など)。

scalendar/views.py


週間カレンダー用のMixinクラスを定義します。
class WeekCalendarMixin(BaseCalendarMixin):
    """週間カレンダーの機能を提供するMixin"""

    def get_week_days(self):
        """その週の日を全て返す"""
        month = self.kwargs.get('month')
        year = self.kwargs.get('year')
        day = self.kwargs.get('day')
        if month and year and day:
            date = datetime.date(year=int(year), month=int(month), day=int(day))
        else:
            date = datetime.date.today().replace(day=1)
        for week in self._calendar.monthdatescalendar(date.year, date.month):
            if date in week:  # 週ごとに取り出され、中身は全てdatetime.date型。該当の日が含まれていれば、それが今回表示すべき週です
                return week

    def get_week_calendar(self):
        """週間カレンダー情報の入った辞書を返す"""
        self.setup()
        days = self.get_week_days()
        first = days[0]
        last = days[-1]
        calendar_data = {
            'now': datetime.date.today(),
            'days': days,
            'previous': first - datetime.timedelta(days=7),
            'next': first + datetime.timedelta(days=7),
            'week_names': self.get_week_names(),
            'first': first,
            'last': last,
        }
        return calendar_data



WeekCalendarMixinの説明


一番重要なメソッドはget_week_calendarメソッドで、これが週間カレンダー構築に必要なものが詰まった辞書を返します。
以下は、辞書の各キーと返すものの説明です。

now


現在の日付で、datetime.date型のオブジェクトを返します。これを使うと、その日が今日なら色をつける...なんてことができます。

days


これは、その週の全ての日を返しています。なので、7つのdatetime.dateオブジェクトが返されます。
月をまたいている日付が出ることもありますが、正しく跨いだ月でのdatetime.date型になっています、安心です。

first


一週間の、最初の日です(datetime.date型)

last


一週間の、最後の日です(datetime.date型)

previous


前の週です。週の始まりを示すfirstを基準に、7日引いているだけです。(datetime.date型)

next


次の週です。週の始まりを示すfirstを基準に、7日足しているだけです(datetime.date型)

MonthCalendarMixinに比べると、大分シンプルですね。

sampleapp/urls.py


/weekと、/week/2018/5/5 のようなURLで、週間カレンダーが表示されます。
year、month、dayといった名前は固定です。年と月と日さえわかればその週を取り出せるので、中なか便利です。
    path('week/', views.WeekCalendar.as_view(), name='week'),
    path('week/<int:year>/<int:month>/<int:day>/', views.WeekCalendar.as_view(), name='week'),


sampleapp/views.py


WeekCalendarMixinを継承するだけです。MonthCalendarMixinを使い方は同じですね。
from django.views import generic
from scalendar.views import MonthCalendarMixin, WeekCalendarMixin
...
...

class WeekCalendar(WeekCalendarMixin, generic.TemplateView):
    """週間カレンダーを表示するビュー"""
    template_name = 'sampleapp/week.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['week'] = self.get_week_calendar()
        return context



week.html


週間カレンダーのテンプレートです。month.htmlと、流れは同じです。
{% extends 'sampleapp/base.html' %}
{% block content %}

<a href="{% url 'sampleapp:week' week.previous.year week.previous.month  week.previous.day %}">前週</a>
{{ week.first | date:"Y年m月d日" }}〜{{ week.last | date:"Y年m月d日" }}
<a href="{% url 'sampleapp:week' week.next.year week.next.month  week.next.day %}">次週</a>
<table class="table">
  <thead>
    <tr>
      {% for w in week.week_names %}
        <th>{{ w }}</th>
      {% endfor %}
    </tr>
  </thead>
  <tbody>
      <tr>
        {% for day in week.days %}
          {% if week.now == day %}
            <td class="table-success">
          {% else %}
            <td>
          {% endif %}
          {% if week.first.month != day.month %}
            {{ day | date:"m/d" }}
          {% else %}
            {{ day.day }}
          {% endif %}
          </td>
        {% endfor %}
      </tr>
  </tbody>
</table>
{% endblock %}
生徒 約15時間前 2018年5月27日22:38 返信する
いつも楽しく拝見しています。
質問させて頂きます。
上記記事のsampleapp/views.pyの中で、先生はWeekCalendarの引数にgeneric.TemplateViewという引数を使用しています。
一方でumedyの講義動画を拝見していると、ブログ作成動画などではclassの引数にTemplateViewを単体で使用しています。
ネット上のdjangoに関する他の記事を見ても、TemplateViewやCreateViewは単体で使うケースが多いように見えるのですが、TemplateViewの前にgenericを付けると、どのような変化があるのでしょうか。
なりと 約14時間前 2018年5月27日23:46
動作としては何もかわりません。

from django.views.generic import CreateView, UpdateView, ListView, DeleteView, TemplateView
のようにするとimportがごちゃごちゃして嫌なので
from django.views import generic
としているだけです。

また、CreateView等の名前はよく使いそうな名前です。
自分で定義するビューは極力これらの名前と衝突しないようにしますが、ソースコードを見てて紛らわしく感じることもあります。
その点、generic.CreateView とするならば汎用ビューのCreateViewという意図がパッと見でわかります。
ただ、結局のところ好みの問題になります。