🐍

Serializer編 -- 忙しい人のためのDjango + DjangoRestFramework

2022/12/24に公開

Serializerとは

https://www.django-rest-framework.org/api-guide/serializers/

dict形式のJSONデータとPythonオブジェクトを相互変換するオブジェクト。

dict → Pythonオブジェクトの変換ではdictの値のバリデーションも行う。

Serializerを定義する

Model編で定義したDivisionモデルのSerializerを作るときは、

  1. rest_framework.serializers.Serializerを継承してクラスを定義する。
  2. 変換先のPythonオブジェクトにある属性をDivisionSerializerクラスにも定義する。
    • ここではDivisionにあるidnameを定義。
  3. 定義した属性id, nameに、変換先のPythonオブジェクトDivisionの属性の型に合わせたserializers.XXXFieldのインスタンスを渡す。
    • ここではidが数値型、nameが文字列型なのでIntegerField, CharFieldを渡す。
    • Fieldの一覧はこちら
from rest_framework import serializers

from api.models import Division

class DivisionSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=30)

ここまでで、Divisionオブジェクト → JSONの変換ができるようになる。

さらに、逆の JSON → Divisionオブジェクト変換を可能にするために、Divisionオブジェクトを生成するメソッドを定義する。

  1. createメソッドとupdateメソッドを作成する。
    • createはdict形式のJSONデータを第一引数に。
    • updateは更新対象のPythonオブジェクト (ここではDivision) を第1引数、dict形式のJSONデータを第2引数に。
  2. createメソッドを、JSONデータからPythonオブジェクトを生成して返すように実装する。
    • ここではDivisionを生成して返す。
  3. updateメソッドを、更新対象オブジェクトの値をJSONデータの値に書き換えて返すように実装する。
    • ここではDivisionオブジェクトdivisionnameを更新してdivision自体を返す。
from rest_framework import serializers

from api.models import Division

class DivisionSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=30)

    def create(self, validated_data: dict):
        """.save()を既存のDivisionを引数に**渡さず**呼ぶ時に使う"""
        division = Division(**validated_data)
        division.save()
        return division

    def update(self, division, validated_data: dict):
        """.save()を既存のDivisionを引数に**渡して**呼ぶ時に使う"""
        division.name = validated_data.get("name", division.name)
        division.save()
        return division

createupdateには追加でなにか操作を加えても良い。ここでは生成/更新したDivisionをDBに保存している。

JSON → Pythonオブジェクト変換

dict形式のJSONデータからPythonオブジェクトを生成するには、まず定義したSerializerインスタンスをJSONデータを渡して生成し、

json_data = {"id": 3, "name": "Development"}
serializer = DivisionModelSerializer(data=json_data)

バリデーションのために.is_valid()を呼び、

serializer.is_valid()  # json_dataの値や型が間違っているとFalseになる。

.save()メソッドを呼ぶ。

division: Division = serializer.save()

バリデーション前にsaveは呼べないので、必ず最初に.is_validを呼び出す。
json_dataの値やその型が間違っていると、.is_validはFalseとなり、.saveは呼べない。

Pythonオブジェクト → JSON変換

Pythonオブジェクトdivision: Divisionからdict形式のJSONデータを生成するには、Pythonオブジェクトを渡してSerializerインスタンスを生成し、.dataにアクセスする。

s = DivisionModelSerializer(division)
json_data: dict = s.data

Modelオブジェクト <-> JSON変換を簡単に書けるModelSerializer

https://www.django-rest-framework.org/api-guide/serializers/#modelserializer

SerializerオブジェクトはDjangoのModelクラスを変換するために定義されることが多いので、Modelクラス専用のクラスModelSerializerが用意されている。これを使うと、最初に定義したDivisionSerializerは以下のように簡単に定義できる。

class DivisionModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = Division
        fields = ["id", "name"]

Metaクラスのmodelに変換先のオブジェクト、fieldsSerializerで変換したいモデルの属性名を指定する。

これだけで、DivisionSerializerと全く同じ動きをする。

Discussion