2013-02-12 14 views
18

Próbuję określić najlepszy sposób dodania elementu głównego do wszystkich odpowiedzi json przy użyciu django i django-rest-framework.Dodawanie elementu głównego do odpowiedzi json (django-rest-framework)

myślę dodając niestandardowy mechanizm renderujący jest najlepszym sposobem, aby osiągnąć to, co chcę osiągnąć i to, co mam wymyślić do tej pory:

from rest_framework.renderers import JSONRenderer 

class CustomJSONRenderer(JSONRenderer): 
#override the render method 
def render(self, data, accepted_media_type=None, renderer_context=None): 
    #call super, as we really just want to mess with the data returned 
    json_str = super(CustomJSONRenderer, self).render(data, accepted_media_type, renderer_context) 
    root_element = 'contact' 

    #wrap the json string in the desired root element 
    ret = '{%s: %s}' % (root_element, json_str) 

    return ret 

Najtrudniejsze teraz jest dynamicznie ustawienie root_element oparciu na widoku, z którego wywoływany jest render().

Wszelkie wskazówki/porady byłyby bardzo mile widziane,

Cheers

Odpowiedz

13

dla potomności, poniżej jest ostatecznym rozwiązaniem. Wzrósł nieznacznie w stosunku do oryginału, ponieważ teraz ponownie formatuje paginowane wyniki.

Również powinienem wcześniej podać, że przyczyną elementu głównego JSON jest integracja z rozwiązaniem front-ember Ember.

serializer:

from rest_framework.serializers import ModelSerializer 
from api.models import Contact 

class ContactSerializer(ModelSerializer): 
    class Meta: 
     model = Contact 
     #define the resource we wish to use for the root element of the response 
     resource_name = 'contact' 
     fields = ('id', 'first_name', 'last_name', 'phone_number', 'company') 

renderujący:

from rest_framework.renderers import JSONRenderer 

class CustomJSONRenderer(JSONRenderer): 
    """ 
     Override the render method of the django rest framework JSONRenderer to allow the following: 
     * adding a resource_name root element to all GET requests formatted with JSON 
     * reformatting paginated results to the following structure {meta: {}, resource_name: [{},{}]} 

     NB: This solution requires a custom pagination serializer and an attribute of 'resource_name' 
     defined in the serializer 
    """ 
    def render(self, data, accepted_media_type=None, renderer_context=None): 
     response_data = {} 

     #determine the resource name for this request - default to objects if not defined 
     resource = getattr(renderer_context.get('view').get_serializer().Meta, 'resource_name', 'objects') 

     #check if the results have been paginated 
     if data.get('paginated_results'): 
      #add the resource key and copy the results 
      response_data['meta'] = data.get('meta') 
      response_data[resource] = data.get('paginated_results') 
     else: 
      response_data[resource] = data 

     #call super to render the response 
     response = super(CustomJSONRenderer, self).render(response_data, accepted_media_type, renderer_context) 

     return response 

paginacja:

from rest_framework import pagination, serializers 

class CustomMetaSerializer(serializers.Serializer): 
    next_page = pagination.NextPageField(source='*') 
    prev_page = pagination.PreviousPageField(source='*') 
    record_count = serializers.Field(source='paginator.count') 

class CustomPaginationSerializer(pagination.BasePaginationSerializer): 
    # Takes the page object as the source 
    meta = CustomMetaSerializer(source='*') 
    results_field = 'paginated_results' 
+0

Dzięki ever.wakeful dla idei, ja też napisałem post o tym, jak go używać z ExtJS frontend (nie muszę inaczej wywoływać elementu głównego, i potrzebuję mieć paginator.count w głównym elemencie) http://kaygorodov.github.io/2014/02/21/extjs-django-rest-framework -root-element.html –

5

zgłosił ever.wakeful uzyskania mi 95% drogi tam.

Osobiście chciałem dodać metadane do każdego żądania interfejsu API dla danego obiektu, niezależnie od tego, czy zostało ono podzielone na strony czy nie. Chciałem też po prostu przekazać obiekt, który zdefiniowałem ręcznie.

Tweaked klienta Renderer

class CustomJSONRenderer(renderers.JSONRenderer): 
    def render(self, data, accepted_media_type=None, renderer_context=None): 
     response_data = {} 
     # Name the object list 
     object_list = 'results' 
     try: 
      meta_dict = getattr(renderer_context.get('view').get_serializer().Meta, 'meta_dict') 
     except: 
      meta_dict = dict() 
     try: 
      data.get('paginated_results') 
      response_data['meta'] = data['meta'] 
      response_data[object_list] = data['results'] 
     except: 
      response_data[object_list] = data 
      response_data['meta'] = dict() 
      # Add custom meta data 
      response_data['meta'].update(meta_dict) 
      # Call super to render the response 
      response = super(CustomJSONRenderer, self).render(response_data, accepted_media_type, renderer_context) 
     return response 

nadrzędna serializer i zobacz Przykład

class MovieListSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = Movie 
     meta_dict = dict() 
     meta_dict['foo'] = 'bar' 

class MovieViewSet(generics.ListAPIView): 
    queryset = Movie.objects.exclude(image__exact = "") 
    serializer_class = MovieListSerializer 
    permission_classes = (IsAdminOrReadOnly,) 
    renderer_classes = (CustomJSONRenderer,) 
    pagination_serializer_class = CustomPaginationSerializer 
    paginate_by = 10 
+0

Czy można użyć tego meta_dict do przekazania wartości z widoku, chcę przekazać request.user w meta_dict –

Powiązane problemy