[Django REST Framework] Serializer の 使い方 についての話

ここではserializersの役割を詳しく見ていこう。

>備考
ビュー については [View の使い方についての話]()を参照してください。
初めて触る方は 先にビュー編を見ることをオススメします。 シリアライザ単体で使うことはまずないと思うので。
この記事の先頭に書いてあったインストールの手順とかはそちらの記事に移動しました
基本的に情報は v3.7.7 時点の [公式ドキュメント](https://www.django-rest-framework.org/) を参考にしました。 一部以下のブログも参照させてもらいました。
[[Django REST Framework] Serializer の 使い方 をまとめてみた](https://note.crohaco.net/2018/django-rest-framework-serializer/)

#serializerとは？

serializerはデータ の入出力を扱い、モデルへの橋渡しをするクラスです。

Serializerの特徴

・複雑な入力値をモデルに合わせてバリデーションしてレコードに伝えたり(入力)

・Model(レコード)を適切な形式にフォーマットしたり(出力)

と言った具合に、 APIの リクエスト / レスポンス に特化した機能を提供します。

#serializer types
Serializerにはいくつか種類があります。

###serializers.Serializer

もっとも単純なシリアライザです。

ここでは学習してきたコードをもとに話を進めていきます。

```python:models.py
class Account(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    fb_id = models.CharField(max_length=30, unique=True)
    ig_id = models.CharField(max_length=30, unique=True)

    def __str__(self):
        return str(self.id)
```

これに対応したシリアライザを以下のように定義しています。

```python:serializers.py
class AccountSerializer(serializers.ModelSerializer):
    fb_code = serializers.CharField(required=False, write_only=True)
    ig_code = serializers.CharField(required=False, write_only=True)
    def create(self, validated_data):
        fb_code = validated_data.get("fb_code")
        ig_code = validated_data.get("ig_code")
        if fb_code:
            return fb_code
        elif ig_code:
            return ig_code
```

ここに書いてあることは単純で、フィールドと保存時の動作がメソッドとして定義されています。フィールドには値に対応した型を記述する。

実際にデシリアライズしていきます。デシリアライズとは入力データをもとに何らかのオブジェクトを作成することです。

#####注意
デシリアライズでは入力値は辞書に準ずる方でなくてはいけません。

まず、data引数に入力データを与えて、`is_valid`メソッドをコールします。

```
>>>from core.models import Account
>>>from core.serializers import AccountSerializer
>>>serializer = AccountSerializer(data={'fb_code':'1234', 'ig_code': '5678'})
>>>serializer.is_valid()
>>>Out[7]: True
>>>serializer.validated_data
>>>Out[8]: OrderedDict([('fb_code', '1234'), ('ig_code', '5678')])
```
続いて、この入力データをオブジェクトとして出力してみます。それを行うのがシリアライズインスタンスのsave()メソッドです。

続いて、この入力データをオブジェクトとして出力してみます。 それを行うのが シリアライザインスタンスの save() メソッドです。 (saveとは言っていますが、単なるSerializerでは永続化はされません)

現在はcreateメソッドしかありませんが、updateメソッドを作ることも可能です。

バリデーションについては後述しますが、シリアライザは`validated_dataと`いう属性を持ち、でしリアライズされたデータのうち、バリデーションを通過した値が格納されています。

バリデーションを行うためのメソッドが`is_valid`です。よって、このメソッドを実行した後でなければ`validated_data`属性を参照することはできませんし、`validated_data`をもとにオブジェクトを生成する`save`メソッドも同様に呼び出すことができません。

##serializers.ModelSerializer

次は`serializers.ModelSerializer`についてです。

おそらく、これが一番利用されることになるSerializerです。

これはModelに紐ずくfieldをSerializerのフィールドとして自動的に定義してくれるものです。

今回はUserモデル用のシリアライザを用意します。

```python:serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
from core.models import Account

class AccountSerializer(serializers.ModelSerializer):
    fb_code = serializers.CharField(required=False, write_only=True)
    ig_code = serializers.CharField(required=False, write_only=True)
    user = UserSerializer(read_only=True)
    class Meta:
        model = Account
        fields = ['id', 'user', 'fb_token' , 'ig_token', 'fb_code', 'ig_code', 'fb_id', 'ig_id']
        read_only_fields = ['user', 'fb_token', 'ig_token', 'fb_id', 'ig_id']

    def create(self, validated_data):
          fb_code = validated_data.get("fb_code")
          ig_code = validated_data.get("ig_code")
          if fb_code:
              return fb_code
          if ig_code:
              return ig_code
```

`create`以下のある`validate_data`属性は入力値を変形するものです。
単純なSerializerでも使えますが、ModelSerializerで使う場合、fieldsに含まれていないと以下のようなエラーになります。

```
AssertionError: The field 'full_name' was declared on serializer UserSerializer, but has not been included in the 'fields' option.
```

先程のSerializerクラスとの違いは`Meta`です。Metaクラスに必須なのは`model`です。
また、`write_only=True`とはSerializerから値は入れたいけど、読み出しはしたくない場合に指定します。


#Fields

次にシリアライザに指定できるフィールドについて解説します。[Serializer_field](https://www.django-rest-framework.org/api-guide/fields/)に詳しい内容が書いてあるのでここでは重要なものだけを解説します。

###Common args

####read_only
・　出力専用のフィールドか否かをBooleanで指定

####write_only
・

####required
・値の指定が必須かどうかをBooleanで指定
・デフォルトはTrueですが、Falseを指定することで入力地に該当フィールドがなくてもスルーしてくれる
・これは入力専用の設定

####default
・値が省略された場合に補完する値を指定

Serializerはかなり理解する部分が多いので徐々に理解していくましょう。