2013-08-30 10 views
15

フィールドの1つが親リソースの値に依存するネストされたリソースを実装しようとしています。Django RESTフレームワーク:ネストされたオブジェクトは、リストビューの親オブジェクトの詳細にアクセスできますか?

顧客に関する情報と会社の営業担当者の売上高を提供する会社のシステムを構築するとします。だから我々は顧客代理人の2つのモデルがあります。担当者は複数の顧客に販売することができます。

すべての顧客を返すURL:特定の顧客のための/api/1.0/customers/

URL:特定の営業担当者のための顧客固有の情報については、/api/1.0/customers/123/

URL:/api/1.0/customers/123/rep/9/

は、担当者のURLは、顧客が含まれていますIDと担当者IDが含まれます。

顧客URLは、担当者に関するサマリー情報とその担当者の顧客固有の完全情報へのハイパーリンクを含むネストされたリソースを返すようにします。我々は2つのシリアライザを定義

[ 
    { 
     "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/" 
       } 
    } 
] 

はこれを実装するには:これは、すべての顧客のためのURLから出力され

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

私が直面しています問題は、私は現在の顧客にアクセスする方法を考え出すことができないということです関数RepSummarySerializer.get_rep_urlからの.id。

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 

ただし、リストビューで、self.parent.objは、Customerオブジェクトのクエリセットであると私は、現在の顧客を識別する任意の方法を見ることができない。顧客がself.parent.objに保持されているように、それは詳細ビューで可能です。これを行う方法はありますか?明白な何かを逃したことがありますか?明瞭の

答えて

20

モーメント:溶液はRepSummarySerializerをインスタンス化のコンテキストでcustomer_idを渡すSerializerMethodFieldを使用することである。

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 

customer_idは次のようにRepSummarySerializer.get_rep_urlでアクセスすることができる。

def get_rep_url(self, obj): 
    customer_id = self.context.get('customer_id') 
    ... 

なぜ私はこの3時間前に考えなかったのか分かりません。

from rest_framework import viewsets 
from rest_framework.decorators import detail_route 
from rest_framework.response import Response 

class CustomerViewSet(viewsets.ModelViewSet): 
    queryset = Customer.objects.all() 
    serializer_class = CustomerSummarySerializer 

    ... 

    @detail_route(methods=['get']) 
    def rep(self, request, pk=None): 
     customer = self.get_object() 
     queryset = customer.pk.all() 
     instances = self.filter_queryset(queryset) 
     serializer = RepSummarySerializer(instances, 
       context={'request': request}, many=True) 
     return Response(serializer.data) 
:あなたはビューセットを使用している場合受け入れ答えに加えて
+0

非常に洗練されたソリューションです。そして、完璧に動作します!どうもありがとう! – gregoltsov

+0

素晴らしい解決策ですが、私はrep = obj.repをrep = obj.rep.get()に変更しなければなりませんでした。 –

2

は、あなたのサブリソースは、(親文書によってフィルタリング)のコレクションだけで、あなたも documented in the docsとして、 @detail_routeデコレータを使用することができますになりたいです

/customers/123/rep/を照会すると、指定した顧客のすべてのRepインスタンスのリストが表示されます。

おそらく完全には解決されませんが、完全にネストされたリソースを必要としない多くの人にとっては、実際には十分です。

関連する問題