14
12

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-11-30

なぜ書いたのか

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で定義されていた関数、自分で定義した関数を呼び出すことが可能

14
12
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
12