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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17256724/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 00:53:46  来源:igfitidea点击:

Include intermediary (through model) in responses in Django Rest Framework

pythondjangodjango-rest-framework

提问by mllm

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

我有一个关于处理 m2m / through 模型及其在 django rest 框架中的演示的问题。我们举一个经典的例子:

models.py:

模型.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:

序列化程序.py:

imports...

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

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

views.py:

视图.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.

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

In other words I expectto 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 itand 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-tastypie 更直接,但还有一些其他问题,更喜欢休息框架。

采纳答案by thebaron

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.fieldwas renamed to serializers.ReadOnlyFieldin DRF 3.0, so this should read:

编辑:正如@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', )

for any modern implementations

对于任何现代实现

回答by FariaC

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:

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

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 中定义自己的创建/更新方法,您可以在其中迭代输入数据并显式创建或更新 Membership 模型实例。

回答by Syed Faizan

NOTE: As a Software Engineer, I love to use Architectures and I have deeply worked on Layered Approach for Development so I am gonna be Answering it with Respect to Tiers.

注意:作为一名软件工程师,我喜欢使用架构,并且我在分层开发方法方面进行了深入研究,所以我将根据层来回答它。

As i understood the Issue, Here's the Solution models.py

正如我所理解的问题,这是解决方案models.py

class Member(models.Model):
    member_id = models.AutoField(primary_key=True)
    member_name = models.CharField(max_length = 

class Group(models.Model):
    group_id = models.AutoField(primary_key=True)
    group_name = models.CharField(max_length = 20)
    fk_member_id = models.ForeignKey('Member', models.DO_NOTHING, 
                             db_column='fk_member_id', blank=True, null=True)

class Membership(models.Model):
    membershipid = models.AutoField(primary_key=True)
    fk_group_id = models.ForeignKey('Group', models.DO_NOTHING, 
                             db_column='fk_member_id', blank=True, null=True)
    join_date = models.DateTimeField()

serializers.py

序列化程序.py

import serializer

class AllSerializer(serializer.Serializer):
    group_id = serializer.IntegerField()
    group_name = serializer.CharField(max_length = 20)
    join_date = serializer.DateTimeField()

CustomModels.py

自定义模型.py

imports...

    class AllDataModel():
        group_id = ""
        group_name = ""
        join_date = ""

BusinessLogic.py

业务逻辑.py

imports ....
class getdata(memberid):
    alldataDict = {}
    dto = []
    Member = models.Members.objects.get(member_id=memberid) #or use filter for Name
    alldataDict["MemberId"] = Member.member_id
    alldataDict["MemberName"] = Member.member_name
    Groups = models.Group.objects.filter(fk_member_id=Member)
    for item in Groups:
        Custommodel = CustomModels.AllDataModel()
        Custommodel.group_id = item.group_id
        Custommodel.group_name = item.group_name
        Membership = models.Membership.objects.get(fk_group_id=item.group_id)
        Custommodel.join_date = Membership.join_date
        dto.append(Custommodel)
    serializer = AllSerializer(dto,many=True)
    alldataDict.update(serializer.data)
    return alldataDict

You would technically, have to pass the Request to DataAccessLayer which would return the Filtered Objects from Data Access Layer but as I have to Answer the Question in a Fast Manner so i adjusted the Code in Business Logic Layer!

从技术上讲,您必须将请求传递给 DataAccessLayer,它会从数据访问层返回过滤后的对象,但由于我必须快速回答问题,所以我调整了业务逻辑层中的代码!