Django REST frameworkで爆速API開発 開発編 serializers その①

エンジニアの島袋です。 開発編ということで、導入編でさらっと触れたDjango REST frameworkの肝の一つであるserializersについて書いて行きたいと思います。 公式ドキュメントのここら辺を参考に書いていきます。 ちなみに爆速なのは開発スピードであって、APIのレスポンスタイムではないです。

導入編
開発編 serializers その① ← 今ココ

serializers

直列変換器(Serializers)という名前の通り、最終的にはmodelデータをJSONで出力するための機能。 表示するデータの選別や表示内容の変更に、バリデーションからのCRUD処理をこのクラスで制御(提供)することができます。

サンプル

下記コマンドで新規Appを作って試していきます。

python manage.py startapp drink

今回は一番需要が高いであろうModelSerializerで紹介していきます。

まず初めにこんなmodels.pyがあるとします。

from django.db import models

class Supplier(models.Model):
    name = models.CharField(max_length=50)
    charge = models.CharField(max_length=50)

class Drink(models.Model):
    name = models.CharField(max_length=50)
    price = models.IntegerField()
    discount = models.IntegerField()
    supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)

対応するserializers.pyファイルを作ります。

from rest_framework import serializers
from .models import Drink, Supplier

class SupplierSerialiser(serializers.ModelSerializer):
    class Meta:
        model = Supplier

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink

view.pyファイルを用意したり、マイグレーションしたり、データをゴニョゴニョ用意して、http://127.0.0.1:8000/drink/を見るとこんなデータを得られます。

{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 1,
            "name": "",
            "price": 100,
            "discount": 75,
            "supplier": 1
        },
        {
            "id": 2,
            "name": "麦茶",
            "price": 110,
            "discount": 100,
            "supplier": 2
        }
    ]
}

ね。簡単でしょ?

表示フィールド

データの中でも表示させたくないものってありますよね? そんな時はこんな風に…

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        fields = ('name', 'price', 'discount')

表示したいのカラムだけを書き加えるだけで、http://127.0.0.1:8000/drink/の表示が…

{
    "name": "",
    "price": 100,
    "discount": 75
}

になるという素敵仕様。

逆に表示したくないカラムを指定したり、

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        exclude = ('supplier',)

特定のカラムを読み込み専用(更新不可)にしたり、

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        read_only_fields = ('name',)

実はurlなんて便利なものがあったり

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        fields = ('name', url)
{
    "count": 2,
    "next": null,
    "previous": null,
    "results": [
        {
            "name": "",
            "url": "http://127.0.0.1:8000/drink/1/"
        },
        {
            "name": "麦茶",
            "url": "http://127.0.0.1:8000/drink/2/"
        }
    ]
}

めちゃくちゃ便利な機能が簡単に利用できます。

外部キーによる参照

実際は上記の表示だけでも運用は可能といえば可能ですが、Drinkクラスのsupplier(仕入先)の情報も同時に欲しいですよね? そんな時はこんな感じで…

class DrinkSerializer(serializers.ModelSerializer):
    supplier = SupplierSerialiser()
    class Meta:
        model = Drink

serializersを書き換えるだけで、http://127.0.0.1:8000/drink/1/の表示が…

{
    "id": 1,
    "supplier": {
        "id": 1,
        "name": "A社",
        "charge": "田中"
    },
    "name": "",
    "price": 100,
    "discount": 75
}

素敵に早変わりします。

ちなみに、下記のようにMetaクラスに1行追加するだけでも同じような結果が得られます。

class DrinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Drink
        depth = 1

簡単すぎて、設計さえガッツリやればコピペだけでいいんじゃないか、というレベルです。

まとめ

というわけで、開発編 serializersクラスの基本的使い方①でした。 serializersは、データを実際にどう見せるかといった制御を行うレイヤーで、DBからデータを取り出し、表示用に加工してViewクラス渡すのが主な仕事に一つになってます。

次回は、開発編 serializersクラスの使い方② InsertやUpdate、バリデーションといったデータの更新周りをお届け予定。