ホーム > 作ってみた > 資産管理 > 資産記録アプリ開発③~Django REST frameworkを使ったAPIの実装~

資産記録アプリ開発③~Django REST frameworkを使ったAPIの実装~

作ってみた資産管理pythondjango

事前準備

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 serializers
from .models import Asset
class AssetSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = "__all__"


Viewの作成

Django REST frameworkにはViewSetsを使った方法なども存在しますが、今回はAPIViewを継承して作成していきます。
APIViewを継承して作成する場合は、必要なHTTPメソッドを全て自分で記述する必要があります。
まずはテーブルのデータをすべて取得するためのGETメソッドを「asset_management/views.py」に作成してみます。
「order_by('created_at')」とすることで、日付順に並べる様にしました。

from rest_framework.views import APIView
from rest_framework.status import HTTP_200_OK
from rest_framework.response import Response
from .models import Asset
from .serializers import AssetSerializer
class 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 admin
from django.urls import path, include
urlpatterns = [
path('api/asset-management/', include('asset_management.urls')), # この行を修正
path('admin/', admin.site.urls),
]

■asset_management/urls.py

from django.urls import path
from . import views
urlpatterns = [
path('v1/assetlist/', views.AssetListAPIView.as_view()), # この行を修正
]

Class-based Viewsを読み込むとき、「as_view()」と記述する必要があるので注意が必要です。



サンプルデータの追加

最低限の動作確認を行うため、とりあえずphpMyAdminの画面からデータを追加しておきます。
20221120193200
20221120193300



API動作確認

http://localhost:8888/api/asset-management/v1/assetlist/
にアクセスし、想定通りのデータが取得できているかどうかを確認します。
20221120193700

DBに登録した通りの値が取得できることが確認できました。



データ追加・更新・削除用APIの作成

合わせて新規データ追加、更新、削除用APIも作成しておきます。
先ほどと同じようにPOST、PUT、DELETEメソッドを作成して処理を記述するのみです。
この時点でフロントエンドのとIFを決めておき、記述していきます。 また、POST時には「diff」「diff_rate」は自動計算。「date」はとりあえず今日の日付を取得して自動で入れるようにします。

from rest_framework.views import APIView
from rest_framework.status import HTTP_200_OK, HTTP_201_CREATED, HTTP_400_BAD_REQUEST
from rest_framework.response import Response
from .models import Asset
from .serializers import AssetSerializer
class 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_amount
diff_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.data
data = {'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用の欄があるのでこれを使います。
20221120194200

下記の様なデータを追加してみます。

{
"asset":"2600000",
"app":"1",
"memo":""
}

成功すると下記のように表示されます。

20221120194700

その他の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)

最低限の作成・確認が出来たので、今回は一旦ここまでとしておきます。