資産記録アプリ開発③~Django REST frameworkを使ったAPIの実装~
事前準備
Django REST frameworkを使用してAPI(バックエンド)を開発していきます。
まずは、下記コマンドでインストールします。
pip install djangorestframework
config/settings.pyに下記の記述を追加します。
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','asset_management','rest_framework', # この行を追加する]
これでDjango REST frameworkを使用するための準備が出来たのでAPIを作っていきます。
Serializerの作成
DBから取り出したモデルオブジェクトをJsonに変換するためのSerializerを用意します。
asset_managementフォルダ配下にserializers.pyを作成し、rest_frameworkの「serializers.ModelSerializer」を継承することで下記のように作ることが可能です。
from rest_framework import serializersfrom .models import Assetclass AssetSerializer(serializers.ModelSerializer):class Meta:model = Assetfields = "__all__"
Viewの作成
Django REST frameworkにはViewSetsを使った方法なども存在しますが、今回はAPIViewを継承して作成していきます。
APIViewを継承して作成する場合は、必要なHTTPメソッドを全て自分で記述する必要があります。
まずはテーブルのデータをすべて取得するためのGETメソッドを「asset_management/views.py」に作成してみます。
「order_by('created_at')」とすることで、日付順に並べる様にしました。
from rest_framework.views import APIViewfrom rest_framework.status import HTTP_200_OKfrom rest_framework.response import Responsefrom .models import Assetfrom .serializers import AssetSerializerclass AssetListAPIView(APIView):def get(self, request):asset = Asset.objects.all().order_by('created_at')serializer = AssetSerializer(asset, many=True)return Response(serializer.data, status=HTTP_200_OK)
URLの設定
先ほど作成したAPIを呼び出すためのルーティングの設定を行います。
「config/urls.py」「asset_management/urls.py」をそれぞれ下記のように修正します。
■config/urls.py
from django.contrib import adminfrom django.urls import path, includeurlpatterns = [path('api/asset-management/', include('asset_management.urls')), # この行を修正path('admin/', admin.site.urls),]
■asset_management/urls.py
from django.urls import pathfrom . import viewsurlpatterns = [path('v1/assetlist/', views.AssetListAPIView.as_view()), # この行を修正]
Class-based Viewsを読み込むとき、「as_view()」と記述する必要があるので注意が必要です。
サンプルデータの追加
最低限の動作確認を行うため、とりあえずphpMyAdminの画面からデータを追加しておきます。
API動作確認
http://localhost:8888/api/asset-management/v1/assetlist/
にアクセスし、想定通りのデータが取得できているかどうかを確認します。
DBに登録した通りの値が取得できることが確認できました。
データ追加・更新・削除用APIの作成
合わせて新規データ追加、更新、削除用APIも作成しておきます。
先ほどと同じようにPOST、PUT、DELETEメソッドを作成して処理を記述するのみです。
この時点でフロントエンドのとIFを決めておき、記述していきます。
また、POST時には「diff」「diff_rate」は自動計算。「date」はとりあえず今日の日付を取得して自動で入れるようにします。
from rest_framework.views import APIViewfrom rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUESTfrom rest_framework.response import Responsefrom .models import Assetfrom .serializers import AssetSerializerclass AssetListAPIView(APIView):def get(self, request):asset = Asset.objects.all()serializer = AssetSerializer(asset, many=True)return Response(serializer.data, status=HTTP_200_OK)# ここから追加した内容def post(self, request):date = dt.date.today()asset_amount = int(request.data['asset'])managed_app = request.data['app']memo = request.data['memo']last_data = Asset.objects.filter(managed_app=managed_app).order_by("created_at").last()diff = asset_amount - last_data.asset_amountdiff_rate = round((asset_amount/last_data.asset_amount-1)*100, 2)data = {'asset_amount': asset_amount,'created_at': date,'diff': diff,'diff_rate': diff_rate,'managed_app': managed_app,'memo': memo}serializer = AssetSerializer(data=data)if serializer.is_valid():serializer.save()return Response(serializer.data, status=HTTP_201_CREATED)return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)def put(self, request):req_data = request.datadata = {'id': req_data['id'], 'asset_amount': req_data['asset_amount'], 'diff': req_data['diff'],'diff_rate': req_data['diff_rate'], 'created_at': req_data['created_at'],'managed_app': req_data['managed_app'], 'memo': req_data['memo']}pre_data = Asset.objects.get(id=data['id'])serializer = AssetSerializer(pre_data, data=data)if serializer.is_valid():serializer.save()return Response(serializer.data, status=HTTP_201_CREATED)return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)def delete(self, request):req_target = request.query_params.get('target')data = Asset.objects.get(id=req_target)data.delete()return Response(status=HTTP_204_NO_CONTENT)
こちらもSerializerを使って簡単に実装することが出来ます。
先ほどと同じように動作確認してみます。
http://localhost:8888/api/asset-management/v1/asset/
へアクセスすると、画面下にPOST用の欄があるのでこれを使います。
下記の様なデータを追加してみます。
{"asset":"2600000","app":"1","memo":""}
成功すると下記のように表示されます。
その他のAPI作成
とりあえずAssetモデルからデータの取得・更新・削除・追加を行うための基本的なAPIは作成しましたが、これだけでは使いにくいので他のAPIも用意しておきます。
特定の情報のみ取得するAPI
例えば、「Zaim」として登録したデータのみ取得するようなAPIです。グラフ表示用データ取得などに使うことを想定しています。
基本的には同じことをやっていくだけなのですが、今回は「query_params.get()」でクエリパラメータを取得するようにします。ここでアプリを指定する想定です。
また、資産額(asset_amouunt)のみを返すように作成するので、先ほど作成したSerializerは使わず、自分で配列を作り、それをreturnするようにしました。
class AssetAmountAPIView(APIView):def get(self, request):req_target = request.query_params.get('target')if req_target:asset = Asset.objects.filter(managed_app__name=req_target)asset = asset.values('asset_amount')asset_list = [{'amount': a['asset_amount']}for a in asset]data_list = []for a in asset_list:data_list.append(a['amount'])return Response({'data': data_list}, status=HTTP_200_OK)
グラフラベル取得API
グラフは縦軸:資産額、横軸:登録日とする予定なので、日付の一覧を取得するAPIを作成しておきます。
とりあえず全アプリ同じ日にデータを登録することを前提とし、1つのアプリの情報のみ取得するようにします。
今回は「Zaim」決め打ちで作成しました。ここを各アプリごとに取得したい場合は、先ほどと同じように
「req_target = request.query_params.get('target')」
とすることで対象アプリを指定できるような作りにすればいいでしょう。
class AssetDateAPIView(APIView):def get(self, request):asset = Asset.objects.filter(managed_app__name='Zaim')asset = asset.values('created_at')asset_list = [{'created_at': a['created_at']}for a in asset]date_list = []for a in asset_list:date_list.append(a['created_at'].strftime('%Y/%m/%d'))return Response({'data': date_list}, status=HTTP_200_OK)
アプリ一覧取得API
アプリマスタからアプリ一覧を取得するAPIです。例えば、データ登録画面を作る際に、セレクトボックスを作ったりするときに使います。
class AppListAPIView(APIView):def get(self, request):app = AppMaster.objects.all().order_by('id')serializer = AppSerializer(app, many=True)return Response(serializer.data, status=HTTP_200_OK)
最低限の作成・確認が出来たので、今回は一旦ここまでとしておきます。