はじめに
初心者ながらバックエンドにDjango REST frameworkを使い、webアプリを作っています。データ一覧のapi表示は出来たのですが、そのデータをごちゃごちゃ計算して表示する方法に中々到達出来なかったので備忘録として残します。初学者なので、ご指摘あれば教えて頂けると嬉しいです。
やりたいこと
以下のようなデータにおいて、date
とhour
をそれぞれ合計し、表示させたいとします。
{
"id": 1
"date": 1
"hour": 2
},
{
"id": 2
"date": 2
"hour": 3
}
APIで表示させたい内容は以下のようなものです。
{
"sum_date": 3
"sum_hour": 5
}
結論
関数ベースビューを用いて実現します。まず結論となるプログラムです。
from django.db.models import Sum
from django.db.models.functions import Coalesce
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Data
@api_view(["GET"])
def get_summary_data(request):
summary_dict = Data.objects.aggregate(
sum_input_date=Coalesce(Sum("date"), 0), sum_input_hour=Coalesce(Sum("hour"), 0)
)
return Response(summary_dict)
@api_viewとは
Httpメソッドを受け取り、それに応じてシリアライズされたデータをAPIに表示できるデコレータです。デコレータとは、関数を受け取り、関数を返す関数です。デコレータについてはとてもわかりやすい記事がありますので、詳しく知りたい方はぜひ。
デフォルトはGETメソッドのみを受け取り、それ以外は405 Method Not Allowed
を返します。他のメソッドを許可したい場合は、次の例のように@api_view
の引数にメソッドを追加します。
@api_view(['GET', 'POST'])
def hello_world(request):
if request.method == 'POST':
return Response({"message": "Got some data!", "data": request.data})
return Response({"message": "Hello, world!"})
aggregate
でデータを加工する
summary_dict = Data.objects.aggregate(
sum_input_date=Coalesce(Sum("date"), 0), sum_input_hour=Coalesce(Sum("hour"), 0)
)
データの加工は、aggregate
で行います。データベースから受け取ったクエリセットを加工し、dictで返します。引数を設定することでキーが生成されるので、上記例だと、sum_input_date
とsum_input_hour
というキーが作られます。
Sum
は、django.db.models
からimportしたもので、データベース上のカラムを合計してくれます。
Coalesce
は、引数に取ったもののうち、nullでない最初のものを返すデータベース関数です。データが一つも入ってない場合に0を返し、エラーを回避しています。
勘違いしていたこと
最初は、annotate
が使えると思って必死に調べてましたが、各データに対しての集計ができるのがannotate
なので今回は使えません。使い方を工夫すればできると思って固執してしまったのが良くありませんでした。
おわりに
振り返れば簡単な内容ですね。3日もかかってしまいました…。でも、aggregate
とannotate
の違いが、使い方も含め明確になったので結果オーライですかね!