Help us understand the problem. What is going on with this article?

DjangoRestFrameworkで中間テーブルをネストした形のJsonで返す

なぜ書いたのか

Django歴が長くはなく、ましてやDRFは初めてで、うまく活用できず悩んだので書いていく。
日本語の記事も少ないと感じたので、少しでも参考になればいいと思う。

Django, djangorestframeworkの説明は省きます。

重要な部分はserializerです。

開発環境

macOS Mojave
python 3.6.7
Django 2.1.3
djangorestframework 3.9.0

Model

まずはDjangoのDocsにも書かれているmodelを例にとってモデルを定義していく

Models | Django documentation | Django

models.py
class Person(models.Model):
    name = models.CharField(max_length=128)
        play = models.CharField(max_length=128)

    def __str__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __str__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

Viewsets

最終的にはそのGroupのMenmberとMenbmerのname,invite_resonを表示したいと考える
viewsetsもここでは重要ではないので最小限に抑える

group_viewsets.py
class GroupViewsets(viewsets.ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

Serialezer

  • 第一段階 MemberのIDがネストされた形のjsonで表示
serializer.py
class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = Group
        fields = (
            'name',
            'members',
        )
{
  "name": "The Beatles",
  "members": [
    1,
    2,
    ...
  ]
}

memberに対してnameとplayも紐付いていて欲しいところ

  • 第二段階

membersに対してPersonの詳細もネストされた状態で紐付いている

serializer.py
class PersonSerializer(serializers.ModelSerializer):
    class Meta:
        model = Person
        fields = (
            'name',
            'play',
        )

class GroupSerializer(serializers.ModelSerializer):
    members = PersonSerializer(many=True)

    class Meta:
        model = Group
        fields = (
            'name',
            'members',
        )
{
  "name": "The Beatles",
  "members": [
    { 
      "name": "Ringo Starr",
      "play": "Drums"
    },
    { 
      "name": "Paul McCartney",
      "play": "Bass"
    },
    ...
  ]
}

Person情報が紐づいたはいいものの、invite_reasonも紐づいて欲しい

  • 第三形態(最終)

membersにinvite_reasonが紐づいたjsonが欲しい

serializers.py
class MembershipSerializer(serializers.ModelSerializer):
    name = serializers.ReadOnlyField(source="person.name")
    play = serializers.ReadOnlyField(source="person.play")

    class Meta:
        model = Membership
        fields = (
            'name',
            'play',
            'invite_reason',
        )

class GroupSerializer(serializers.ModelSerializer):
    members = MembershipSerializer(source='membership_set', many=True)

    class Meta:
        model = Group
        fields = (
            'name',
            'members',
        )

最初はMemberhipSerializerからpersonにアクセスしてnameをとるという発想ができなかった、僕はここでつまづきました.djangoの特性などがわかっていればすぐにできそうですが、、、

MembershipSerializerのperson=Personserializer()などやって、全然できずに悩んでいました.

{
  "name": "The Beatles",
  "members": [
    { 
      "name": "Ringo Starr",
      "play": "Drums",
      "invite_reason": "Needed a new drummer."
    },
    { 
      "name": "Paul McCartney",
      "play": "Bass"
      "invite_reason": "Wanted to form a band."
    },
    ...
  ]
}

これで思い通りの結果を取得できるようになりました。

今回学んだポイント

serializersのReadOnlyFieldやCharFieldで定義されていた関数、自分で定義した関数を呼び出すことが可能

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away