2016-02-18 29 views
7

Utilizzo Django 1.6 (molto presto l'aggiornamento a 1.8), Python 2.7 e DRF 3.2.5 (molto presto l'aggiornamento all'ultima versione).Estendere il framework del resto django per consentire l'ereditarietà del contesto nei serializzatori nidificati

Ho una serie di serializzatori profondamente annidati (~ 10 livelli di profondità, con un totale di 20-30 modelli serializzati). Sto tentando di aggiungere un flag booleano al contesto, che determinerà se la gerarchia dell'output serializzato sarà dettagliata (include tutti i campi dei modelli) o di base (solo parte dei campi).

ho scritto il seguente codice (frammento di parziale):

from rest_framework import serializers 
from app.models import Institute, Department, Member 

class MemberSerializer(serializers.ModelSerializer): 
    def get_fields(self): 
     fields = super(MemberSerializer, self).get_fields() 
     if self.context['basic_view']: 
      for field in ['height', 'weight']: 
       del fields[field] 
     return fields 

    class Meta: 
     model = Member 
     fields = ('id', 'birth_date', 'height', 'weight') 


class DepartmentSerializer(serializers.ModelSerializer): 
    members = MemberSerializer(many=True, read_only=True) 

    def get_fields(self): 
     fields = super(DepartmentSerializer, self).get_fields() 
     if self.context['basic_view']: 
      for field in ['type', 'manager']: 
       del fields[field] 
     return fields 

    class Meta: 
     model = Department 
     fields = ('id', 'name', 'type', 'manager', 'members') 


class InstituteSerializer(serializers.ModelSerializer): 
    departments = DepartmentSerializer(many=True, read_only=True) 

    def get_fields(self): 
     fields = super(InstituteSerializer, self).get_fields() 
     if self.context['basic_view']: 
      for field in ['name', 'type']: 
       del fields[field] 
     return fields 

    class Meta: 
     model = Institute 
     fields = ('id', 'name', 'type', 'departments') 

def get_entities(is_basic_view): 
    institutes_list = Institute.objects.all() 

    serializer = InstituteSerializer(institutes_list, many=True, read_only=True, context={'basic_view': is_basic_view}) 

    return serializer.data 

Ma poi scoperto che il 'contesto' che viene passato da 'get_entities' a 'InstituteSerializer' non viene passato-on per i serializzatori nidificati . Significa che nell'esempio sopra - InstituteSerializer ha 'basic_view' nel 'contesto', ma MemberSerializer & DepartmentSerializer no.

Ho trovato una soluzione di lavoro in context in nested serializers django rest framework: per utilizzare SerializerMethodField per campo nidificato (ad esempio "reparti") e nel metodo 'get_' per passare manualmente il contesto. Il mio problema con questa soluzione è che è necessario incorporare questo codice 20-30 volte nel mio codice, eventualmente raddoppiando il numero di linee di origine.

La mia richiesta - se qualcuno ha (o può aiutare a implementare) un'estensione per serializers.ModelSerializer, che otterrà un parametro aggiuntivo al momento della costruzione, ad es. 'Inherit_context'. Quindi l'unica cosa che ho bisogno di cambiare nelle mie classi, per esempio in 'InstituteSerializer', è l'aggiunta di quel parametro:

class InstituteSerializer(serializers.ModelSerializer): 
    departments = DepartmentSerializer(many=True, read_only=True, inherit_context=True) 

    def get_fields(self): 
     fields = super(InstituteSerializer, self).get_fields() 
     if self.context['basic_view']: 
      for field in ['name', 'type']: 
       del fields[field] 
     return fields 

    class Meta: 
     model = Institute 
     fields = ('id', 'name', 'type', 'departments') 
+0

Forse non capisco bene, ma perché non si passa semplicemente a quel contesto? Per esempio. chiamando 'dipartimenti = DepartmentSerializer (many = True, read_only = True, context = self.context)' da 'InstituteSerializer' con il contesto che ha ricevuto in precedenza? – C14L

+0

@ C14L non è possibile poiché 'self' è un riferimento non risolto a questo punto –

risposta

8

A quanto pare ho perso qualcosa ... Il 'contesto' è già ereditato fino ai serializzatori nidificate ...

Tuttavia, la ragione per cui non ha funzionato per me, è perché, come parte della mia nidificazione, alcuni dei serializzatori bambino sono state definite tramite serializers.SerializerMethodField() . E in tal caso (solo!) il contesto è non automaticamente ereditato.

La soluzione è passare-on semplicemente il 'contesto', all'interno del metodo 'ottenere _...' relative a ciascun SerializerMethodField:

class ParentSerializer(serializers.ModelSerializer): 
    child = serializers.SerializerMethodField() 

    def get_child(self, obj): 
     child = .... 
     serializer = ChildSerializer(instance=child, context=self.context) 
     return serializer.data 

PS - un problema di DRF github simile al mio stato creato un tempo fa: https://github.com/tomchristie/django-rest-framework/issues/2555