はじめに
バックエンド開発をしているとフロントエンドができるだけ処理しやすい形データを渡してあげたいなぁと思いますよね?(フロントエンドの開発したことないんですが。。。)
初学者だけど!
シリアライザの使いわけ方がわからなかった
+
親子関係を持つモデルを返却する際に階層を揃える方法
の2点を備忘録として残しておきます。
モデルのイメージ
データの取得
大前提としてDjangoでは子テーブルから親テーブル参照することができます。
今回であれば以下のように、子から親を参照しに行くことができるんですね。
data = テーブルA.objects.select_related("テーブルB", "テーブルC").all()
-本題- データ返却(Serializerの準備)
Serialzerを準備していきます。
・問題点
以下のようなシリアライザにすると次の様な形式で出力されてしまう。
class TableBSerializer(serializers.ModelSerializer):
"""テーブルB(親)のシリアライザ"""
class Meta:
model = TableB
fields = ["id", "value_b"]
class TableCSerializer(serializers.ModelSerializer):
"""テーブルC(親)のシリアライザ"""
class Meta:
model = TableC
fields = ["id", "value_c"]
class TableASerializer(serializers.ModelSerializer):
"""テーブルA(子)のシリアライザ"""
tableB = TableBSerializer() # テーブルBのシリアライザをネスト
tableC = TableCSerializer() # テーブルCのシリアライザをネスト
class Meta:
model = TableA
fields = ["id", "vlaue_a", "tableB", "tableC"]
レスポンスは以下の通り
{
# テーブルAのキーをマッピングできていない
"id": 0,
"vlaue_a": "string",
"tableB": {
"id": 0,
"value_b": "value_b"
},
"tableC": {
"id": 0,
"value_c": "value_c"
}
}
理想はtable_a
をキーとしてマッピングすることである。
{
"tableA": {
"id": 0,
"value_a": "value_a"
},
"tableB": {
#~~~~~~~省略~~~~~~~~~~~
}
・ModelSerailzerは単一のモデルを扱うもの
ModelSerializer
はモデルをネストもできるが基本的には単一モデルの操作向き
変更点:
ModelSerializerで内包するのではなく、Serializerで内包することにした
class TableASerializer(serializers.ModelSerializer):
"""テーブルA(子)のシリアライザ"""
class Meta:
model = TableA
fields = ["id", "vlaue_a"]
class TableBSerializer(serializers.ModelSerializer):
"""テーブルB(親)のシリアライザ"""
class Meta:
model = TableB
fields = ["id", "value_b"]
class TableCSerializer(serializers.ModelSerializer):
"""テーブルC(親)のシリアライザ"""
class Meta:
model = TableC
fields = ["id", "value_c"]
# serializers.Serializerに変更
class AllDataSerializer(serializers.Serializer):
"""新規追加: 返却用シリアライザ"""
tableA = TableASerializer()
tableB = TableBSerializer()
tableC = TableCSerializer()
{
"tableA": {
"id": 0,
"value_a": "value_a"
},
"tableB": {
"id": 0,
"value_b": "value_b"
},
"tableC": {
"id": 0,
"value_c": "value_c"
}
}
フラットになりました
おまけ
取得したデータはtableAを起点として取得したものである。
上記の修正を行ってもでエラーが発生する場合は、以下の追記をすることで解消することが可能である。
class AllDataSerializer(serializers.Serializer):
"""返却用シリアライザ"""
tableA = TableASerializer(source="*")
tableB = TableBSerializer()
tableC = TableCSerializer()
※source="*"
は自身のインスタンスを全て渡すオプションである。これによりソースを参照することができるようになる。