2
3

More than 3 years have passed since last update.

[DRF]apiの作成(post)

Last updated at Posted at 2021-03-17

Django-rest-framework勉強中です

前回前々回の記事のpostバージョンです。

準備

前回と同じですが、一応Model構成載せておきます。

models.py
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"
            ),
        ]
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番

post

今回はpostです。リソースの登録をする役割のあるメソッドですが、実際の運用ではもうちょっといろいろなことをやらせるAPIを準備しなくてはならないのかなと思います。

一旦はリソースの登録をするAPIを作成してみます。

レコードの新規作成

restの原則では、postはリソースの作成(CRUDで言うC)を行い、冪等性は保証しません。まぁ、今回はあまり気にせずDRFの書き方みたいな感じで軽く書いてみようかなと思います。

serializer

まぁ、getのときと一緒です。
ModelSerializerを継承して、studentモデルの全カラムを作成しにいきます。

serializers.py
from rest_framework import serializers
from ..models import Student


class StudentSerializer(serializers.ModelSerializer):
    """Studentクラスのシリアライザ"""

    class Meta:
        model = Student
        fields = '__all__'

view

簡単に書いています。実際の業務だともうちょい複雑なコードになるかもです。
リクエストをデシリアライズした後、serializer.is_valid()というメソッドを呼んでいます。一度バリデーションを通さないと次のserializer.save()が呼べないことになっています。validationの内容は、デフォルトではModelSerializerであればModelの定義に即しているかのみのチェックです。
例えば生徒情報IDというフィールドでは、

student_id = models.CharField(max_length=4, primary_key=True)

このようにModelを定義しているので、max_lengthが4文字かどうかなどのチェックがかかるということがわかります。

そしてその後の.save()で、SQLのcreate文が流れるという感じです。

views.py
from rest_framework.response import Response
from rest_framework.views import APIView

from ..serializers.student_create import StudentSerializer


class StudentCreateAPIView(APIView):
    """
    生徒情報新規登録API
    """

    def post(self, request, *args, **kwargs):

        # リクエストをシリアライズ
        serializer = StudentSerializer(data=request.data)

        # リクエストのバリデーション
        serializer.is_valid(raise_exception=True)

        # リソースの新規作成(create)
        serializer.save()

        # レスポンス
        return Response({'result':True})

url

pkはパスパラメータでなくbodyに入れることとしています。

urls.py
from django.urls import path
from . import views

urlpatterns = [
    # path('<pk>/retrieve/', views.StudentRetrieveAPIView.as_view())
    # path('<class_no>/<int:attendance_no>/retrieve/', views.StudentRetrieveAPIView.as_view()),
    path('create/', views.StudentCreateAPIView.as_view())
]

いざ実行

apitest.py
import requests

student_id='0006'
class_no='1'
attendance_no=4
name="黒崎一護"
district_no='4'
comment='尸魂界'
body = {
    'student_id':student_id,
    'class_no':class_no,
    'attendance_no':attendance_no,
    'name':name,
    'district_no':district_no,
    'comment':comment,
}
response = requests.post('http://127.0.0.1:8000/student/create/', body)
print(response.text)    # レスポンスのHTMLを文字列で取得

一意制約に気をつけて実行したところ、viewで定義したとおりresult:trueが返ってきました。
そして以下のレコードができていました!!

STUDENT ID CLASS NO ATTENDANCE NO NAME DISTRICT NO COMMENT
0006 1 4 黒崎一護 地区4 尸魂界

ちなみに・・・

validationに引っかかると、以下のようにエラーで教えてくれます。
student_id='00007'でリクエストすると、以下エラーとなります。

rest_framework.exceptions.ValidationError: {'student_id': [ErrorDetail(string='この項目が4文字より長くならないようにしてください。', code='max_length')]}

汎用APIViewも使ってみたい

views.pyを以下のように変えてみました。

views.py
from rest_framework import generics

from ..models import Student
from ..serializers import StudentSerializer


class StudentCreateAPIView(generics.CreateAPIView):
    queryset = Student.objects.all()
    serializer_class = StudentSerializer

実行

apitest.py
import requests

student_id='0007'
class_no='1'
attendance_no=5
name="朽木ルキア"
district_no='4'
comment='袖白雪'
body = {
    'student_id':student_id,
    'class_no':class_no,
    'attendance_no':attendance_no,
    'name':name,
    'district_no':district_no,
    'comment':comment,
}
# response = requests.get('http://127.0.0.1:8000/student/{}/retrieve/'.format(id))
response = requests.post('http://127.0.0.1:8000/student/create/', body)
print(response.text)    # レスポンスのHTMLを文字列で取得

できちゃった・・・。

STUDENT ID CLASS NO ATTENDANCE NO NAME DISTRICT NO COMMENT
0007 1 5 朽木ルキア 地区4 袖白雪

本当にコード量が少ないですね・・・。

ひとまず、postリクエストでリソースの新規作成ができました。
次はリソースの一部更新(patch? put?) をして基礎編は終了したいと思います。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3