django-rest-frameworkを勉強しています
まだ初心者なのですが、DRFの勉強中です。
公式は英語だし、ググってもなかなか体系化された情報が出てこなくて苦労しています。
コードを読んでも「なんでこのコードだけでDB取得できるの!?」と思わされることが多く・・・。
勉強がてら、サンプルコードを書きながら意味のわからない用語や単語については解説していければと思います。勉強中なので変な書き方、もっと良い書き方等あるかと思いますが、ご容赦ください。(コメントなどで教えていただければ・・・。)
今回の記事では
DRFでgetのAPIを作成する際のコードを書いていきます。今回は単一オブジェクトのみの取得です。
getの中でも単一行取得だったり、複数行の取得だったりがあると思うので、両方のパターンを今後見ていけたらと思います。また、もしあれば「こんなパターンもあるよね」と横道にそれて行こうと思います。
準備
Djangoプロジェクトの作成や管理サイトについての説明は省きます。
まず、以下のようなModelを用意します。
from django.db import models
DISTRICT_CATEGORIES = [
(1, "地区1"),
(2, "地区2"),
(3, "地区3"),
(4, "地区4"),
]
class Student(models.Model):
"""生徒情報"""
# 生徒ID
student_id = models.CharField(max_length=4, primary_key=True)
# クラス
class_no = models.CharField(max_length=1)
# 出席番号
attendance_no = models.IntegerField()
# 名前
name = models.CharField(max_length=20)
# 地区番号
district_no = models.CharField(max_length=1, choices=DISTRICT_CATEGORIES)
# フリーコメント
comment = models.CharField(max_length=200,blank=True)
class Meta:
constraints = [
models.UniqueConstraint(
fields=["class_no", "attendance_no"],
name="class_attendance_unique"
),
]
せっかくなのでCharFieldだけじゃなくIntegerFieldだったり、Choiceの設定などもしています。また、クラス・出席番号での生徒の取得もしたいので、UniqueConstraint(クラス、出席番号のペアは一意)の成約を加えました。
また、とりあえず以下のデータを管理サイトから作成しておきました。
STUDENT ID | CLASS NO | ATTENDANCE NO | NAME | DISTRICT NO | COMMENT |
---|---|---|---|---|---|
0005 | 2 | 2 | fugafuga | 地区1 | 2組2番 |
0004 | 2 | 1 | hogehoge | 地区2 | 2組1番 |
0003 | 1 | 3 | 山田3番 | 地区4 | 1組3番 |
0002 | 1 | 2 | 山田花子 | 地区2 | 1組2番 |
0001 | 1 | 1 | 山田太郎 | 地区1 | 1組1番 |
get
では、このmodelに対して、一覧や単一行を取得するコードを書いてみましょう。
pkから単一行取得
今回、modelでstudent_idをpkにしていますので、これを使えばデータの単一行での取得は可能です。
serializer
serializerって?
一応自己の理解のために簡単な説明を入れておきますね。
オブジェクトのシリアライズ・デシリアライズをすることができます。シリアル(直列)化ですね。ネットワークでの通信が必要な場合、受け取ったデータをデシリアライズしてdjangoで扱えるようにしたり、シリアライズして送ったりするようです。ここも詳しく今後調べて行けるといいなーと思います。
serializerを作成します
取得をしたあと、レスポンスを作成するためのserializerを作成します。
from rest_framework import serializers
from .models import Student
class StudentSerializer(serializers.ModelSerializer):
"""Studentクラスのシリアライザ"""
class Meta:
model = Student
fields = '__all__'
StudentModelに紐付いたシリアライザです。fieldはallとしています。
view
viewって?
djangoのviewと同じです。
リクエストを受け取り、レスポンスを作成して返すところまでの処理をします。
viewを作成します
from django.shortcuts import get_object_or_404
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Student
from .serializers import StudentSerializer
class StudentRetrieveAPIView(APIView):
def get(self, request, pk, *args, **kwargs):
"""Studentをpkで取得"""
# モデルのオブジェクト取得
instance = get_object_or_404(Student, pk=pk)
# シリアライズ
serializer = StudentSerializer(instance)
# 返却
return Response(serializer.data, status.HTTP_200_OK)
get_object_or_404はdjangoが用意してくれているものですね。get_objectで1件の取得を表している感じでしょうか。
※もうちょっと便利なクラスを継承してコードの量減らしてもいいのですが、今回は勉強混じりということで、そちらは後ほど紹介します!
ここで、get
メソッドの引数にpk
という項目が存在しますね。
このpk
はurls.pyで指定が可能です。
以下のとおりです。
urls.py
urls.pyで以下のように、呼び出されるURLとそれに応じて呼ばれるViewが対応つけられます。
プロジェクトディレクトリのurls.pyは以下の記述
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('student/', include('students.urls'))
]
(adminについては気にしなくて大丈夫です)
studentsアプリの配下にはurls.pyを作成して以下の記述をします。
from django.urls import path
from . import views
urlpatterns = [
path('<pk>/retrieve/', views.StudentRetrieveAPIView.as_view())
]
実行
ここまでで、serializer,view,urlsの準備ができたので実際にAPIを実行してみましょう。
実行ファイルはこちらです。
import requests
id='0001'
response = requests.get('http://127.0.0.1:8000/student/{}/retrieve'.format(id))
print(response.text) # レスポンスのHTMLを文字列で取得
{"student_id":"0001","class_no":"1","attendance_no":1,"name":"山田太郎","district_no":"1","comment":"1組1番"}
想定のものが返ってきました。よかったー。
pk以外の複数の値から単一行取得
次はクラスと出席番号から、行を取得します。
変更するのはurlとviewの部分です。
urls.py
URLでクラス、出席番号を指定してもらいます。
urlpatterns = [
- path('<pk>/retrieve/', views.StudentRetrieveAPIView.as_view())
+ path('<class_no>/<int:attendance_no>/retrieve/', views.StudentRetrieveAPIView.as_view())
]
views.py
getの引数にURLから受け取ったものを加え、get_objectの際のキーに指定します。
class StudentRetrieveAPIView(APIView):
- def get(self, request, pk, *args, **kwargs):
+ def get(self, request, class_no, attendance_no, *args, **kwargs):
"""Studentをclass_no, attendance_noで取得"""
# モデルのオブジェクト取得
- instance = get_object_or_404(Student, pk=pk)
+ instance = get_object_or_404(Student, class_no=class_no, attendance_no=attendance_no)
# シリアライズ
serializer = StudentSerializer(instance)
# 返却
return Response(serializer.data, status.HTTP_200_OK)
実行
import requests
id='0001'
class_no='1'
attendance_no=2
# response = requests.get('http://127.0.0.1:8000/student/{}/retrieve'.format(id))
response = requests.get('http://127.0.0.1:8000/student/{}/{}/retrieve'.format(class_no, attendance_no))
print(response.text)
{"student_id":"0002","class_no":"1","attendance_no":2,"name":"山田花子","district_no":"2","comment":"1組2番"}
できた!
とりあえず、getについてのAPIを作ってみました。
複数オブジェクトの取得とか、もっと便利なAPIViewを使って簡単にかけると思いますので、引き続き次回以降の記事で勉強していきます。