DJangoシリアル化における外部キー値の表現


シリアライザの主な目的は、JSON出力やXML出力などのインターネット上で転送できる形式にDjangoモデルまたはデータベーステーブルを変換することです.
あなたが外国のキーまたは多くの多くの関係を通して互いに関連している2つのモデルを持っているとき、これはわずかにトリッキーになります.畝
別のモデルに外部キーを含むモデルをシリアル化するには、このデータをどうするかによって様々な方法で行うことができます.最も広く使われているメソッドは入れ子になったシリアライザーを使うことです.

入れ子シリアライザの使用
歌と芸術家の関係を考えてください.このように外国のキーの必要を必要とする同じアーティストに属するかもしれない複数の歌があるかもしれません.
from django.db import models

class Artist(models.Model):
  name = models.CharField(max_length=255)

  def __str__(self):
    return self.name

class Song(models.Model):
  name = models.CharField(max_length=255)
  artist = models.ForeignKey(Artist, related_name="songs", on_delete=models.CASCADE)

  def __str__(self):
    return self.name
それはアーティストによって記録されたすべての曲を含む方法でアーティストモデルを提示したいとしましょう.これはネストしたシリアライザーを使用して実現できます.
from rest_framework import serializers
from .models import Song, Artist


class SongSerializer(serializers.ModelSerializer):
    class Meta:
      model = Song
      fields = ('id', 'name', 'artist')

class ArtistSerializer(serialisers.ModelSerializer):
  songs = SongSerializer(many=True)

  class Meta:
    model = Artist
    fields = ('id', 'name', 'songs')
ArtistSerializerを使用すると、返される応答は次のようになります
{
  "id": 1,
  "name": "Beatles",
  "songs": [
    {
      "id": 1,
      "name": "I am the walrus"
    },
    {
      "id": 2,
      "name": "Come together"
    }
   ]
}
デフォルトではネストされたシリアライザは読み取り専用です.このシリアライザーを使用して、入力とデータをDBに書き込むには、次のように明示的にcreate ()またはupdate ()メソッドをオーバーライドしなければなりません.
from rest_framework import serializers
from .models import Song, Artist


class SongSerializer(serializers.ModelSerializer):
    class Meta:
      model = Song
      fields = ('id', 'name', 'artist', 'duration_in_seconds')

class ArtistSerializer(serialisers.ModelSerializer):
  songs = SongSerializer(many=True)

  def create(self, validated_data):
    songs_data = validated_date.pop("songs")
    artist = Artist.objects.create(**validated_data)
    for song_data in songs_data:
      Song.objects.create(artist=artist, song=**song_data)
    return artist

  class Meta:
    model = Artist
    fields = ('id', 'name', 'songs')

デフォルトシリアライザー関係の使用
ネストされたserializersを書くには、通常、あなたがhereを見つけることができるDjango RESTフレームワークによって提供される様々なタイプのシリアライザー関係を使用することによって回避できます.畝
このチュートリアルでは、PrimiyKeyRelededFieldとSurglLaedFieldをカバーします.シリアライザー関連の型の残りはかなり似ており、ユースケースに応じてこれらと互換性があります.
これらの型では、ReadRank Only = trueを設定するだけで、読み取り専用のシリアル化を作成できます.また、入力を有効にすることでデータを書き込むこともできます.
書き込み可能にする場合は、単に入力を検証するために使用されるReadRadio Only = False Sumと共にシリアライザーにQuerySetパラメータを含める必要があります.畝
これをさらに説明するために最も一般的に使用されるシリアライザー関係を見てみましょう

PrimaryKeyRelatedField
既に関連するフィールドの個々のオブジェクトを持っている場合は、オブジェクトを識別するためにプライマリキーをシリアル化できます.
from rest_framework import serializers
from .models import Song, Artist

class ArtistSerializer(serialisers.ModelSerializer):
  songs = serializers.PrimaryKeyRelatedField(many=True, read_only=True)

  class Meta:
    model = Artist
    fields = ('id', 'name', 'songs')
これは次のようにシリアル化されます.
{
  "id": 1,
  "name": "Beatles",
  "songs": [
    1,
    2
   ]
}
このシリアライザーを書き込み可能にするには、次の引数を使用します.
from rest_framework import serializers
from .models import Song, Artist

class ArtistSerializer(serialisers.ModelSerializer):
  songs = serializers.PrimaryKeyRelatedField(
    many=True, 
    read_only=False,
    queryset=Song.objects.all()
  )

  class Meta:
    model = Artist
    fields = ('id', 'name', 'songs')

スラブフィールド
関係のターゲットがプライマリキー以外のフィールドを使用して表される必要がある場合は、使用するフィールドを指定できます.
from rest_framework import serializers
from .models import Song, Artist

class ArtistSerializer(serialisers.ModelSerializer):
  songs = serializers.SlugRelatedField(
    many=True, 
    read_only=True,
    slug_field="name"
  )

  class Meta:
    model = Artist
    fields = ('id', 'name', 'songs')
これは次のようにシリアル化されます.
{
  "id": 1,
  "name": "Beatles",
  "songs": [
    "I am the walrus",
    "Come together"
   ]
}

クロージングノート
データのシリアル化時にオブジェクトやリレーションシップの作成/表現を完全に制御する必要がある場合や、シリアル化の際にオブジェクト全体を表示する必要がある場合は、ネストされたSerializersを使用して、より良いアプローチが必要です.
しかし、既に関連するモデルにアクセスできるアプリケーションを構築していて、それらを参照するための識別子が必要な場合は、組み込みのシリアライザー関係のいずれかを使用することをお勧めします.
serializersの外部キーリレーションを扱う上記のメソッドは、foreignkeyフィールドだけではありません.また、Manytomanyfieldとonetoonefieldに適用されます.