DRFのViewについてまとめる
2020-11-27
こんにちは
どうも、こんにちは、僕です。
今日はDRFのなんちゃらAPIViewについてまとめたいと思います。
自分の推しはAPIViewです。対戦お願いします!
DRFとは?
そんなもんは自分で調べてください(辛辣)
参考までにこれは[前回の記事](https://www.takurinton.com/post/32)でさらっと書いてしまったAPIView周りの深堀りみたいなイメージで描いていきます。
今回使うモデル
今回使うモデルはとてもシンプルで、以下のようなものを想定しています。
Userを格納するためのモデルで、nameには名前、ageには年齢、sexには性別が入るようになっています。
種類
DRFのViewには様々な種類があります。
また、関数で実装する場合やクラスで実装する場合などがあります。
大大大大大前提
ここで少し前提として知っておくと嬉しいことについてメモ程度に書いておきます。
関数ベースで使う場合
関数ベースでViewを使用する時にはデコレータを使用してAllow methodを指定してその下にリクエストが来た時の関数を定義してあげます。これをしないとみんな大好き405エラーが返ってきてお陀仏です。
実際の使い方は以下のようになっています。
from rest_framework.response import Response
from rest_framework.decorators import api_view
@api_view(['GET', 'POST'])
def user(request):
if request.method == 'GET':
user = User.objects.filter(is_active=True)
res = {'message': 'ok', 'user': user}
return Response(res, status=status. HTTP_200_OK)
else:
data = request.data
user = User(name=data['name'], age=data['age'], sex=data['sex'])
user.save()
res = {'message': 'ok'}
return Response(res, status=status. HTTP_201_CREATED)
こんな感じです。
処理自体は簡単で、get requestがきたらユーザー全取得、post requestがきたらユーザー登録をするようになっています。
クラスベースで使う場合
クラスベースでDRFのViewを使用する場合は大きく分けて2つに分類されます。
2つのいずれもクラスを継承して実装することになります。
データベースに紐づくやつ
これはシリアライザーを作成していい感じにしていく手法です。
まあ公式がこれ継承して使えばええで!って言ってるので使います。
これがまた書きやすいんですよね、可読性とかコードの追いやすさは置いておいて、とても簡単にデータベースから値を出すことができます。
また、これを使うときにはGeneric Viewというものを使用します。これには複数の種類があります。
これらのメソッドがあり、それぞれの特性に合わせて継承して扱います。
さらにこいつらは組み合わせて使用することができます。詳しくは[こちら](https://www.django-rest-framework.org/api-guide/generic-views)を見てみてください。
また、シリアライザーとしてDBのオブジェクトを渡してあげるとよしなにやってくれます。
例えばこんな感じ
# serialyzer.py
from rest_framework import serializers
from .models import User
# シリアライズの対象を指定する
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User # 取得したいモデル
fields = '__all__' # フィールドをタプル、またはリストで渡す。全部欲しい時は__all__で取得できる
このようにしてシリアライザーを定義します。ここでMetaクラスの中に取得したいモデルとフィールドを指定することでそのオブジェクトと指定したフィールドの値を取得することができます。
# views.py
from .serializer import UserSerializer
class UserView(generics.ListAPIView):
serializer_class = UserSerializer # 先ほど指定したシリアライザーを指定
queryset = User.objects.filter(is_active=True) # クエリを指定
今回は一覧取得がしたかったのでListAPIViewを使用しました。
ここでserializerという変数に先ほど作成したシリアライザーを渡すことで先ほど指定したモデルのオブジェクトを取得してくれます。
とても短いコードになりました。これは強い。
ですが個人的にはこれは汎用性に欠ける気がしていてそこまで好きではありません。ちなみにquerysetに生のSQLを渡すこともできますが好きくない。
データベースに紐づかないやつ
圧倒的にこっち派です。
このやり方はAPIViewを継承して実装をします。
from rest_framework.response import Response
from rest_framework.views import APIView
class UserView(APIView):
def get(self, request):
user = User.objects.filter(is_active=True)
res = {'message': 'ok', 'user': user}
return Response(res, status=status. HTTP_200_OK)
def post(self, request):
data = request.data
user = User(name=data['name'], age=data['age'], sex=data['sex'])
user.save()
res = {'message': 'ok'}
return Response(res, status=status. HTTP_201_CREATED)
ほうらわかりやすい!直感的い!シリアライザー使わなくていいのでとっても嬉しいのです。今回は生のSQL書いてないので影響はなさそうですが、今後書くってなったときに一部ではシリアライザー、一部ではAPIViewを使用して実装してるとわかりにくいのでこうして統一させたい感はあります。
また、N+1問題をいい感じにやっつけるためにも生のSQLは大事になってくるので積極的に利用していきたいです。
まとめ
シリアライザーは最初はわかりにくい部分とかも多いのですが、わかれば使いやすくて便利だなと感じています。
これ外部キーとかの取得どうするんだろう?とかもし外部キー取得できるならどういうクエリが発行されるんだろうかとかとても気になることがたくさんあるので調べてまた記事にしたいと思います。
Django、便利ですね、またね。