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

mll*_*llm 96 python django django-rest-framework

我有一个关于处理m2m /通过模型及其在django rest框架中的表示的问题.我们来看一个经典的例子:

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()
Run Code Online (Sandbox Code Playgroud)

serializers.py:

imports...

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

class GroupSerializer(ModelSerializer):
    class Meta:
        model = Group
Run Code Online (Sandbox Code Playgroud)

views.py:

imports...

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

class GroupViewSet(ModelViewSet):
    queryset = Group.objects.all()
    serializer_class = GroupSerializer
Run Code Online (Sandbox Code Playgroud)

在获取成员实例时,我成功接收了所有成员的字段及其组 - 但是我只获得了组的详细信息,而没有来自成员模型的额外详细信息.

换句话说,我希望收到:

{
   'id' : 2,
   'name' : 'some member',
   'groups' : [
      {
         'id' : 55,
         'name' : 'group 1'
         'join_date' : 34151564
      },
      {
         'id' : 56,
         'name' : 'group 2'
         'join_date' : 11200299
      }
   ]
}
Run Code Online (Sandbox Code Playgroud)

注意join_date.

我已经尝试了很多解决方案,当然包括关于它的Django Rest-Framework官方页面,似乎没有人给出一个合适的简单答案 - 我需要做些什么才能包含这些额外的字段?我发现它更直接与django-tastypie但有一些其他问题,更喜欢休息框架.

小智 126

怎么样.....

在MemberSerializer上,在其上定义一个字段,如:

groups = MembershipSerializer(source='membership_set', many=True)
Run Code Online (Sandbox Code Playgroud)

然后在您的会员序列化程序上,您可以创建:

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', )
Run Code Online (Sandbox Code Playgroud)

这具有创建序列化值的整体效果,组具有所需的成员资格,然后它使用自定义序列化程序来提取要显示的位.

编辑:由@bryanph评论,在DRF 3.0中serializers.field重命名为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', )
Run Code Online (Sandbox Code Playgroud)

任何现代实施

  • `membership_set`是Member - > Membership的默认相关名称 (3认同)
  • 费伊,我已经尝试了很多变种,但无法正常工作。这不是官方文档吗?成员集在哪里定义? (2认同)
  • 对我来说,棘手的部分是发现“membership_set”名称。我有一个没有明确“相关”名称的直通模型,因此我必须通过阅读 [Django Many to Many](https://docs.djangoproject.com/en/1.9/topics) 上的文档来猜测它的名称/db/examples/many_to_many/)。 (2认同)

小智 13

我遇到了这个问题,我的解决方案(使用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]
Run Code Online (Sandbox Code Playgroud)

这将返回groups键的dicts列表,其中每个dict都是从MembershipSerializer序列化的.要使其可写,您可以在MemberSerializer中定义自己的创建/更新方法,在该方法中迭代输入数据并显式创建或更新成员资格模型实例.