知識の枝

"All is well"

Django 期間で区切ったデータをテンプレートに渡す

約385日前 2021年4月27日21:19
デジタル
Django

改訂履歴


2021/4/27 投稿

1. 背景


Djangoを使った開発中に覚えたことを備忘録として残します。

今回はモデルを期間で区切り、ある時間条件を満たすモデルのみをhtmテンプレートに渡す方法を解説します。


2. ゴール


タスクアプリで納期が●ヵ月以内のタスクのみ一覧表示する。


3. はじめに


タスクアプリをイメージしてみて下さい。

タスクを登録するとき「いつまでにやる必要があるか?」つまり、納期を設定する場合があると思います。

私は忘れっぽいので、結構先の予定までタスクアプリに登録しています。
抜け漏れ無く管理できるのは良いのですが、1つ問題が生じます。

タスク一覧画面を開くと全部のタスクが表示されます。
本来やるべきタスクが優先度の低いタスクに埋もれてしまうので、このままでは使い勝手が悪いですよね。


そこで解決策として、納期の近いタスクのみを一覧表示することにします。
Djangoのクエリセットを日時でフィルターすれば実装可能なので、その方法を次項で解説します。


4. 日時でフィルター


タスクの納期が3ヵ月以内のものを表示する場合を考えます。

「納期の日付 < 今日から3ヵ月後の日付」のタスクを抽出すれば目的の結果になりそうです。

では「今日から3ヵ月後の日付」はどうやって表現したら良いでしょうか?
答えは「relativedelta」です。

relativedeltaを使うと「何日後の日付」、「何ヵ月前の日付」などを簡単に取得できるようになります。


まずインポートしましょう。
from dateutil.relativedelta import relativedelta


「今日から3ヵ月後の日付」は下記のように表すことができます。
today_after_3month = datetime.date.today() + relativedelta(months=3)
今日の日付に3ヵ月足しただけです。


「今日から14日前」だったら下記のようになります。
two_weeks_ago = datetime.date.today() - relativedelta(day=14)
直感的に使うことができます。


views.pyの中で上記の処理を実行し、フィルターを掛けたあとのデータをテンプレートに渡します。
views.py
class PtaskView(generic.ListView):
template_name = 'task_management_layout.html'
model = Task

def get_context_data(self, **kwargs):
today_after_3month = datetime.date.today() + relativedelta(months=3)

context = super().get_context_data(**kwargs)
context['task_plan_3month'] = Task.objects.filter(set_date__lt=today_after_3month)
return context
汎用ビューが持つ「get_context_data」メソッドを使い、テンプレートへ渡す変数を定義します。

関数の中でまず始めに先ほど出てきた「今日から3ヵ月後の日付」を定義します。
today_after_3month = datetime.date.today() + relativedelta(months=3)


「task_plan_3month」という変数に日付フィルターを掛けたTaskモデルを入れます。
context['task_plan_3month'] = Task.objects.filter(set_date__lt=today_after_3month)


「filter(括弧)」の中にフィルタリングする条件を書いています。
set_date__lt=today_after_3month


ここで「set_date」はタスクモデル作成時に入力した「納期」を表します。
models.py
class Task(models.Model):
"""Task info"""
task = models.CharField(verbose_name='やること', max_length=255, blank=True, null=True)
set_date = models.DateField('いつまでに', blank=True, null=True) #ここが納期の部分「set_date」

def __str__(self):
return self.task

「set_date」が「今日から3ヵ月後の日付」より小さければ良いので、filterのメソッド「__lt」を使います。

「__lt」はアンダースコア×2個と「l(Less)」と「t(Than)」です。
したがって先ほどの条件式は「set_date less than today_after_3month」と読めます。


filterメソッドには他にも「__gt(Greater Than)」など便利なフィルタリング条件がたくさんあります。

Django公式ドキュメントに使用例が載っていますのでぜひ参考にして下さい。
Making queries


5. さいごに


モデルから必要な情報のみ抽出できるようになると、出来ることの幅がぐんと広がります。

メソッドをすべて覚える必要は無いと思います。
必要になったときに「あぁこんな方法があったな」と思い出して調べればOKです!
お疲れ様でした。