2013-08-30 9 views
15

Sto tentando di implementare una risorsa nidificata in cui uno dei suoi campi dipende da un valore dalla sua risorsa padre.Framework Rango di Django: un oggetto nidificato può accedere ai dettagli dell'oggetto principale in una visualizzazione elenco?

Supponiamo di costruire un sistema per un'azienda che fornisce informazioni sui propri clienti e cifre di vendita per i venditori dell'azienda. Quindi abbiamo due modelli, Cliente e Rep. Un rappresentante può vendere a più di un cliente.

URL che restituisce tutti i clienti: /api/1.0/customers/

URL per un cliente specifico: /api/1.0/customers/123/

URL per informazioni specifiche del cliente per una specifica rappresentante: /api/1.0/customers/123/rep/9/

Nota l'URL rappresentante contiene il cliente ID e l'ID rappresentante.

Desidero che l'URL del cliente restituisca una risorsa nidificata contenente informazioni di riepilogo sul rappresentante, oltre a un collegamento ipertestuale a informazioni complete specifiche del cliente per tale rappresentante. Questa è l'uscita dal URL per tutti i clienti:

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

Per attuare questo definiamo due serializzatori:

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

Il problema che sto affrontando è che non riesco a capire come accedere il cliente corrente .id dalla funzione RepSummarySerializer.get_rep_url. E 'possibile in una vista di dettaglio come il cliente è tenuto in 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 

Tuttavia, in una vista elenco, self.parent.obj è un QuerySet di oggetti del cliente e non riesco a vedere alcun modo di identificare il cliente corrente. C'è un modo per farlo? Ho perso qualcosa di ovvio?

risposta

20

momento di chiarezza: la soluzione è quella di utilizzare un SerializerMethodField per un'istanza RepSummarySerializer e passare il customer_id nel contesto:

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 

Il customer_id ora possibile accedere in RepSummarySerializer.get_rep_url simili:

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

Non so perché non ci ho pensato tre ore fa.

+0

Una soluzione elegante.E funziona perfettamente! Molte grazie! – gregoltsov

+0

Ottima soluzione, ma ho dovuto cambiare rep = obj.rep in rep = obj.rep.get() –

2

Oltre alla risposta accettata, se si utilizza viewsets e volete che il vostro sub-risorsa da una raccolta (filtrato dal documento principale) solo, è anche possibile utilizzare il @detail_route decoratore, come documented in the docs:

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) 

Ora è possibile richiedere /customers/123/rep/ e si otterrà un elenco di tutte le istanze Rep per il cliente specificato.

Probabilmente non risolverà completamente ciò che è necessario, ma per molte persone che non hanno bisogno di risorse nidificate complete è in realtà sufficiente.

Problemi correlati