Django REST框架:嵌套对象可以在列表视图中访问其父对象的详细信息吗?

Dav*_*ull 17 django django-rest-framework

我试图实现一个嵌套资源,其中一个字段依赖于其父资源的值.

假设我们正在为一家公司建立一个系统,该系统提供有关其客户的信息以及该公司销售人员的销售数据.所以我们有两个模型,CustomerRep.代表可以向多个客户出售.

返回所有客户的URL: /api/1.0/customers/

特定客户的URL: /api/1.0/customers/123/

特定销售代表的客户特定信息的URL: /api/1.0/customers/123/rep/9/

请注意,rep URL包含客户ID和代表ID.

我希望客户URL返回一个嵌套资源,其中包含有关代表的摘要信息,以及指向该代表的完整客户特定信息的超链接.这是所有客户的URL输出:

[
    {
        "id": 100, 
        "customer_name": "DolManSaxLil",
        "rep": {
                "id": 4,
                "annual_sales": 1500.01,
                "name": "Fred",
                "url": "http://localhost:8000/api/1.0/customer/100/rep/4/"
               }
    },
    {
        "id": 200, 
        "customer_name": "Hotblack",
        "rep": {
                "id": 4,
                "annual_sales": 10500.42,
                "name": "Fred",
                "url": "http://localhost:8000/api/1.0/customer/200/rep/4/"
               }
    }
]
Run Code Online (Sandbox Code Playgroud)

为实现这一点,我们定义了两个序列化器

class CustomerSummarySerializer(serializers.HyperlinkedModelSerializer):
    id = ...
    name = ...
    rep = RepSummarySerializer(read_only=True)

class RepSummarySerializer(serializers.HyperlinkedModelSerializer):
    id = ...
    annual_sales = ...
    name = ....
    url = serializers.SerializerMethodField('get_rep_url')
Run Code Online (Sandbox Code Playgroud)

我面临的问题是我无法弄清楚如何从函数中访问当前的customer.id RepSummarySerializer.get_rep_url. 在详细信息视图中可以将客户保留在self.parent.obj:

def get_rep_url(self, obj):
    customer_id = self.parent.obj.id
    url = reverse('api_customer_rep', 
              kwargs={'customer_id': customer_id,
                      'rep_id': obj.id},
                      request=serializer.context.get('request'))
    return url
Run Code Online (Sandbox Code Playgroud)

但是,在列表视图中,self.parent.obj是Customer对象的QuerySet,我看不到任何识别当前Customer的方法.有没有办法做到这一点?我错过了一些明显的事吗?

Dav*_*ull 20

清晰的时刻:解决方案是使用a SerializerMethodField实例化RepSummarySerializer并传递customer_id上下文:

class CustomerSummarySerializer(serializers.HyperlinkedModelSerializer):
    id = ...
    name = ...
    rep = serializers.SerializerMethodField('get_rep')


    def get_rep(self, obj):
        rep = obj.rep
        serializer_context = {'request': self.context.get('request'),
                              'customer_id': obj.id}
        serializer = RepSummarySerializer(rep, context=serializer_context)
        return serializer.data
Run Code Online (Sandbox Code Playgroud)

customer_id现在可以访问在RepSummarySerializer.get_rep_url像这样的:

def get_rep_url(self, obj):
    customer_id = self.context.get('customer_id')
    ...
Run Code Online (Sandbox Code Playgroud)

不知道为什么我三小时前没想到这个.