Django-rest-frameworkでAPIを作成します
前回までの記事一覧です。
基本編 |
---|
[DRF]apiの作成(patch) |
[DRF]apiの作成(post) |
[DRF]apiの作成(get)part2 |
[DRF]apiの作成(get)part1 |
応用編 |
---|
[DRF]結合テーブルの更新(part2) |
[DRF]結合テーブルの更新(part1) |
[DRF]結合テーブルの取得 |
前回の記事では、drf-writable-nestedを使用して、結合テーブルを新規作成しました。今回はupdate()
メソッドのオーバーライドにより更新をしてみようと思います。
model
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"
),
]
class Exam(models.Model):
"""試験情報"""
# 国語
japanese_score = models.IntegerField(null=True, blank=True)
# 数学
math_score = models.IntegerField(null=True, blank=True)
# 英語
english_score = models.IntegerField(null=True, blank=True)
# 生徒ID
student = models.OneToOneField(Student, on_delete=models.CASCADE)
StudentとExamが1対1対応しています。
update
今回は既存レコードを更新します。
view
viewは前回(create)と変わっていません。
とりあえず何も考えず、既存の普通のレコードの更新のように書いています。
partial=True
もついてます。
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from ..models import Student
from ..serializers import StudentExamUpdateSerializer
class StudentExamUpdateAPIView(APIView):
"""生徒情報、試験情報を登録"""
def post(self, request, pk, *args, **kwargs):
instance = get_object_or_404(Student, pk=pk)
# serializer作成
serializer = StudentExamUpdateSerializer(instance=instance, data=request.data, partial=True)
# validate
try:
serializer.is_valid(raise_exception=True)
except Exception:
raise Exception
serializer.save()
# Response
return Response({'result':True})
serializer(未完成)
クラスの名前だけ変えました。
from rest_framework import serializers
from ..models import Student, Exam
class ExamOfStudentExamUpdateSerializer(serializers.ModelSerializer):
"""Examクラスのシリアライザ"""
class Meta:
model = Exam
fields=[
'japanese_score',
'math_score',
'english_score'
]
class StudentExamUpdateSerializer(serializers.ModelSerializer):
"""Studentクラスのシリアライザ"""
exam = ExamOfStudentExamUpdateSerializer()
class Meta:
model = Student
fields = [
'student_id',
'class_no',
'attendance_no',
'name',
'district_no',
'comment',
'exam'
]
実行
実行ファイルは以下のとおりです。
urls.pyは貼りませんが、パスパラメータでpkをもらってそのpkに対して更新しにいきます。
名前と数学の点数を修正しにいきます。
import requests
import json
student_id='0001'
name="更木剣八"
math_score = 30
exam = {
'math_score': math_score,
}
body = {
'name':name,
}
headers = {"Content-Type" : "application/json;charset=UTF-8"}
response = requests.post('http://127.0.0.1:8000/student/{}/student_exam_update/'.format(student_id), data=json.dumps(body), headers=headers)
print(response.text)
AssertionError: The
.update()
method does not support writable nested fields by default.
Write an explicit.update()
method for serializerstudents.serializers.student_exam_update.StudentExamUpdateSerializer
, or setread_only=True
on nested serializer fields.
やっぱり怒られました。しょうがない、updateをオーバーライドしてみましょうか。
serializer(完成)
updateを追加しています。
from rest_framework import serializers
from ..models import Student, Exam
class ExamOfStudentExamUpdateSerializer(serializers.ModelSerializer):
"""Examクラスのシリアライザ"""
class Meta:
model = Exam
fields=[
'japanese_score',
'math_score',
'english_score'
]
class StudentExamUpdateSerializer(serializers.ModelSerializer):
"""Studentクラスのシリアライザ"""
exam = ExamOfStudentExamUpdateSerializer()
class Meta:
model = Student
fields = [
'student_id',
'class_no',
'attendance_no',
'name',
'district_no',
'comment',
'exam'
]
+ def update(self, instance, validated_data):
+
+ exam_data = validated_data.pop('exam')
+ instance = super().update(instance, validated_data)
+
+ exam_serializer = ExamOfStudentExamUpdateSerializer(instance=instance.exam, data=exam_data)
+ exam_serializer.is_valid()
+ exam_serializer.save()
+
+ return instance
再実行
{"result":true}
出来ました。
serializerがあれば、これを使用してupdateとすることができそうです。
こちらを参考にしました。
個人的にとっても迷う実装だったのですが、参考リンクのおかげでなんとなく腹落ちしました。
次回はWritableNestedModelSerializer
でupdateします。