2016-05-17 9 views
7

È un compito piuttosto normale in Django REST Framework fornire ulteriori args/kwargs a un serializzatore per impostare i valori dei campi impostati non tramite request.data, ma tramite il valore nei parametri url o cookie. Per esempio, ho bisogno di impostare il campo user del mio modello Comment uguale a request.user su richiesta POST. Questi argomenti aggiuntivi sono chiamati contesto.Django REST Framework: come funziona il contesto serializzatore?

Molte domande (1, 2) su StackOverflow suggeriscono che sovrascrivo get_serializer_context() metodo della mia ModelViewSet. Ho fatto e non aiuta. Ho cercato di capire, cosa c'è che non va, e ho scoperto che non capisco dal codice sorgente, come dovrebbe funzionare questo sistema di contesto in generale. (manca anche la documentazione su questo argomento)

Qualcuno può spiegare, dove serializzatore aggiunge contesto ai dati di richiesta normale? Ho trovato due posti, dove salva i valori dal contesto.

  1. serializer.save(), metodo, che si mescola con kwargs dati convalidati, ma di solito è chiamato senza argomenti (per esempio mediante ModelMixins).
  2. fields.__new__(), che memorizza in cache args e kwargs, ma sembra che nessuno li abbia mai letti più tardi.

risposta

7

Ogni volta che si utilizza una vista generici o viewsets, DRF (3.3.2) aggiunge request oggetto, view oggetto e format al serializzatore context. È possibile utilizzare serializer.context per accedere, diciamo request.user nel serializzatore.

Questo viene aggiunto quando viene chiamato get_serializer_class(). Al suo interno, chiama il metodo get_serializer_context() in cui tutti questi parametri vengono aggiunti al suo contesto.

DRF codice sorgente di riferimento:

class GenericAPIView(views.APIView): 
    """ 
    Base class for all other generic views. 
    """ 

    def get_serializer(self, *args, **kwargs): 
     """ 
     Return the serializer instance that should be used for validating and 
     deserializing input, and for serializing output. 
     """ 
     serializer_class = self.get_serializer_class() 
     kwargs['context'] = self.get_serializer_context() 
     return serializer_class(*args, **kwargs)  

    def get_serializer_context(self): 
     """ 
     Extra context provided to the serializer class. 
     """ 
     return { 
      'request': self.request, 
      'format': self.format_kwarg, 
      'view': self 
     } 
+0

Questo ho capito, ma cosa succede dopo? Non riesco a vedere, dove Serializer utilizza questo contesto per riempire i campi con valori, presi da esso. –

+0

In casi normali il contesto non verrà utilizzato da un serializzatore. Se vogliamo accedere all'oggetto 'request' in un serializzatore, useremo' self.context.get ('request') '. Inoltre, nel metodo 'to_representation' di qualsiasi campo del serializzatore, possiamo accedere al' context' usando la variabile 'self.context'. –

+0

(da [docs] (http://www.django-rest-framework.org/api-guide/serializers/#including-extra-context)) Un caso comune per includere 'context' è se si sta utilizzando un serializzatore che include relazioni ipertestuali, che richiede che il serializzatore abbia accesso alla richiesta corrente in modo che possa generare correttamente URL completi. –

0

per impostare i valori di campi non impostati tramite request.data, ma tramite il valore di parametri URL o biscotti. Ad esempio, ho bisogno di impostare il campo utente del mio modello Comment uguale a request.user su richiesta POST.

Questo è come gestire entrambi i casi nel mio ModelViewSet:

def perform_create(self, serializer): 

    # Get article id from url e.g. http://myhost/article/1/comments/ 
    # obviously assumes urls.py is setup right etc etc 
    article_pk = self.kwargs['article_pk'] 
    article = get_object_or_404(Article.objects.all(), pk=article_pk) 

    # Get user from request 
    serializer.save(author=self.request.user, article=article) 

Purtroppo gli oggetti nidificati non è standard per DRF ma questo è oltre il punto. :)