DjangoでTruncateをかける方法について解説します。使い方としては、created_atなどのDatetimeFieldを使用している場合で、月別、日別、年別のデータが欲しい時などに使用できるかと思います。こういった時は大体グラフで表示すると思うのですが、今回はグラフ描画の方法については置いておきます。
例えば、以下のようにやりたいとします。
{
date: ‘2022年1月1日’,
count: 3,
date: ‘2022年1月2日’,
count: 1,
date: ‘2022年1月3日’,
count: 0,
date: ‘2022年1月4日’,
count: 5,
}
modelの構造が、例えば以下のような形で
class Message(models.Model): title = models.CharField(verbose_name='メッセージ件名', null=True, blank=True, max_length=400) content = models.TextField(verbose_name='メッセージ本文') created_at = models.DateTimeField(verbose_name='登録日', auto_now_add=True) updated_at = models.DateTimeField(verbose_name='更新日', auto_now=True)
Messageの件数をcreated_at、つまり登録日でGroup化して取得したいという場合です。
DjangoではTruncというものが用意されている。詳しくは公式ドキュメントを参照してください。
さて、こういった状況で、まずは月別データの取得ですが、基本的にはどのTruncを使用する場合も同じです。Model.annotate().values(Trunc).annotate()という記述をすることで目的を達成することができます。
下記に先立ってTruncに使用するものをimportする必要があります。
from django.db.models.functions import TruncMonth, TruncDay, TruncYear
- 日別データの取得
messages = self.queryset.annotate( day=TruncDay('created_at') ).values('day').annotate(count=Count('pk'))
- 月別データの取得
messages = self.queryset.annotate( day= TruncMonth('created_at') ).values('day').annotate(count=Count('pk'))
- 年別データの取得
messages = self.queryset.annotate( day= TruncYear('created_at') ).values('day').annotate(count=Count('pk'))
このように記述をすると、下記のようにデータを取得することができます(下記は、日別データの取得になります)。
[{"day":"2021年12月30日","count":8},{"day":"2021年12月31日","count":1}]
なお、上記はDatetimeFieldをdatetime.datetime.strftimeで文字列に変換しています。
for message in messages: message['day'] = datetime.datetime.strftime(message['day'], '%Y年%m月%d日')
グラフにて描画する(実は今回はvuetifyとvue-chartjsを使用しています)ためには、API側で日付の操作をしておいた方が楽なので(フロント側で行ってもいいのですが、Pythonの方が楽なため)上記のような実装になっています。
もし誰かのお役に立てれば幸いです。
====================================================
株式会社ハードコアでは、営業ツールとして麻波25を開発中です。
こういった機能が欲しいなどご要望があればお気軽にご連絡ください。