在Django Rest框架的响应中包含中介(通过模型)

时间:2021-12-20 20:40:42

I have a question about dealing with m2m / through models and their presentation in django rest framework. Let's take a classic example:

我有一个关于如何处理m2m /通过模型以及他们在django rest框架中的演示的问题。让我们举一个经典的例子:

models.py:

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:

serializers.py:

imports...

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

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

views.py:

views.py:

imports...

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

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

When GETing an instance of Member, I successfully receive all of the member's fields and also its groups - however I only get the groups' details, without extra details that comes from the Membership model.

当GETing一个成员的实例时,我成功地接收了所有成员的字段和它的组,但是我只获得了组的细节,没有来自成员模型的额外细节。

In other words I expect to receive:

换句话说,我期望收到:

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

Note the join_date.

注意join_date。

I have tried oh so many solutions, including of course Django Rest-Framework official page about it and no one seems to give a proper plain answer about it - what do I need to do to include these extra fields? I found it more straight-forward with django-tastypie but had some other problems and prefer rest-framework.

我尝试了很多解决方案,当然包括Django Rest-Framework官方页面,但是似乎没有人给出一个合适的简单的答案——我需要做什么来包含这些额外的字段?我发现django-无味派更直接,但也有其他问题,更喜欢rest-framework。

2 个解决方案

#1


94  

How about.....

.....怎么样

On your MemberSerializer, define a field on it like:

在MemberSerializer中,定义一个字段,比如:

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

and then on your membership serializer you can create this:

然后在你的会员序列化器上你可以创建这个:

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', )

That has the overall effect of creating a serialized value, groups, that has as its source the membership you want, and then it uses a custom serializer to pull out the bits you want to display.

它的总体效果是创建一个序列化的值组,组作为您想要的成员关系的源,然后它使用一个自定义序列化器提取您想要显示的位。

EDIT: as commented by @bryanph, serializers.field was renamed to serializers.ReadOnlyField in DRF 3.0, so this should read:

编辑:正如@bryanph评论的那样,序列化器。字段被重命名为序列化器。ReadOnlyField在DRF 3.0,所以这应该读:

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', )

for any modern implementations

对于任何现代实现

#2


4  

I was facing this problem and my solution (using DRF 3.6) was to use SerializerMethodField on the object and explicitly query the Membership table like so:

我遇到了这个问题,我的解决方案(使用drf3.6)是在对象上使用SerializerMethodField,并明确地查询成员表:

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]

This will return a list of dicts for the groups key where each dict is serialized from the MembershipSerializer. To make it writable, you can define your own create/update method inside the MemberSerializer where you iterate over the input data and explicitly create or update Membership model instances.

这将返回组键的命令列表,其中每个命令都从MembershipSerializer序列化。为了使其可写,您可以在MemberSerializer内定义自己的创建/更新方法,在该方法中迭代输入数据并显式地创建或更新成员模型实例。

#1


94  

How about.....

.....怎么样

On your MemberSerializer, define a field on it like:

在MemberSerializer中,定义一个字段,比如:

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

and then on your membership serializer you can create this:

然后在你的会员序列化器上你可以创建这个:

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', )

That has the overall effect of creating a serialized value, groups, that has as its source the membership you want, and then it uses a custom serializer to pull out the bits you want to display.

它的总体效果是创建一个序列化的值组,组作为您想要的成员关系的源,然后它使用一个自定义序列化器提取您想要显示的位。

EDIT: as commented by @bryanph, serializers.field was renamed to serializers.ReadOnlyField in DRF 3.0, so this should read:

编辑:正如@bryanph评论的那样,序列化器。字段被重命名为序列化器。ReadOnlyField在DRF 3.0,所以这应该读:

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', )

for any modern implementations

对于任何现代实现

#2


4  

I was facing this problem and my solution (using DRF 3.6) was to use SerializerMethodField on the object and explicitly query the Membership table like so:

我遇到了这个问题,我的解决方案(使用drf3.6)是在对象上使用SerializerMethodField,并明确地查询成员表:

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]

This will return a list of dicts for the groups key where each dict is serialized from the MembershipSerializer. To make it writable, you can define your own create/update method inside the MemberSerializer where you iterate over the input data and explicitly create or update Membership model instances.

这将返回组键的命令列表,其中每个命令都从MembershipSerializer序列化。为了使其可写,您可以在MemberSerializer内定义自己的创建/更新方法,在该方法中迭代输入数据并显式地创建或更新成员模型实例。