web-dev-qa-db-ja.com

Django Rest Frameworkの応答に中間モデルを介して)を含める

Django restフレームワークでのモデルとそのプレゼンテーションを介したm2m /の取り扱いについて質問があります。古典的な例を見てみましょう。

models.py:

from Django.db import models

class Member(models.Model):
    name = models.CharField(max_length = 20)
    groups = models.ManyToManyField('Group', through = 'Membership')

class Group(models.Model):
    name = models.CharField(max_length = 20)

class Membership(models.Model):
    member = models.ForeignKey('Member')
    group = models.ForeignKey('Group')
    join_date = models.DateTimeField()

serializers.py:

imports...

class MemberSerializer(ModelSerializer):
    class Meta:
        model = Member

class GroupSerializer(ModelSerializer):
    class Meta:
        model = Group

views.py:

imports...

class MemberViewSet(ModelViewSet):
    queryset = Member.objects.all()
    serializer_class = MemberSerializer

class GroupViewSet(ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer

メンバーのインスタンスを取得すると、メンバーのすべてのフィールドとそのグループを正常に受け取りますが、メンバーシップモデルからの追加の詳細なしで、グループの詳細のみを取得します。

言い換えれば、Iexpectを受信する:

{
   'id' : 2,
   'name' : 'some member',
   'groups' : [
      {
         'id' : 55,
         'name' : 'group 1'
         'join_date' : 34151564
      },
      {
         'id' : 56,
         'name' : 'group 2'
         'join_date' : 11200299
      }
   ]
}

join_dateに注意してください。

もちろん Django Rest-Framework official page about it を含む非常に多くのソリューションを試してみましたが、誰もそれについて適切な明白な答えを出していないようです-これらの追加フィールドを含めるために何をする必要がありますか? Django-tastypieの方がわかりやすいのですが、他にもいくつか問題があり、レストフレームワークを好みます。

94
mllm

どうでしょう.....

MemberSerializerで、次のようにフィールドを定義します。

groups = MembershipSerializer(source='membership_set', many=True)

そして、メンバーシップシリアライザーでこれを作成できます。

class MembershipSerializer(serializers.HyperlinkedModelSerializer):

    id = serializers.Field(source='group.id')
    name = serializers.Field(source='group.name')

    class Meta:
        model = Membership

        fields = ('id', 'name', 'join_date', )

これは、必要なメンバーシップをソースとして持つシリアル化された値、グループを作成し、カスタムシリアライザーを使用して表示するビットを引き出します。

編集:@bryanphのコメント通り、serializers.fieldはDRF 3.0でserializers.ReadOnlyFieldに名前が変更されたため、次のようになります。

class MembershipSerializer(serializers.HyperlinkedModelSerializer):

    id = serializers.ReadOnlyField(source='group.id')
    name = serializers.ReadOnlyField(source='group.name')

    class Meta:
        model = Membership

        fields = ('id', 'name', 'join_date', )

最新の実装向け

122
thebaron

私はこの問題に直面しており、私のソリューション(DRF 3.6を使用)は、オブジェクトでSerializerMethodFieldを使用し、Membershipテーブルを次のように明示的にクエリすることでした。

class MembershipSerializer(serializers.ModelSerializer):
    """Used as a nested serializer by MemberSerializer"""
    class Meta:
        model = Membership
        fields = ('id','group','join_date')

class MemberSerializer(serializers.ModelSerializer):
    groups = serializers.SerializerMethodField()

    class Meta:
        model = Member
        fields = ('id','name','groups')

    def get_groups(self, obj):
        "obj is a Member instance. Returns list of dicts"""
        qset = Membership.objects.filter(member=obj)
        return [MembershipSerializer(m).data for m in qset]

これにより、各ディクショナリがMembershipSerializerからシリアル化されるグループキーのディクテーションのリストが返されます。書き込み可能にするには、MemberSerializer内で独自の作成/更新メソッドを定義して、入力データを反復処理し、メンバーシップモデルインスタンスを明示的に作成または更新できます。

13
FariaC