2013-02-12 114 views
18

我想確定使用django和django-rest-framework將根元素添加到所有json響應的最佳方法。將根元素添加到json響應(django-rest-framework)

我想添加自定義渲染器是實現我想達到什麼是最好的方式,這就是我來了這麼遠:

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 

棘手的部分現在被動態地設置root_element基於認爲render()正在被調用。

任何指針/建議將不勝感激,

乾杯

回答

13

對於後代,下面是最終溶液。它從原來的略有增長,因爲它現在也重新分頁分頁結果。

此外,我應該在之前指出,JSON根元素的原因是與Ember前端解決方案集成。

串行:

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

渲染:

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 

分頁:

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

感謝ever.wakeful一個想法,我也寫了一篇關於我如何與ExtJS的前端使用它後(我不需要以不同的方式調用根元素,而且我需要在根元素中包含paginator.count)http://kaygorodov.github.io/2014/02/21/extjs-django-rest-framework -root-element.html – 2014-02-20 20:21:24

5

感謝ever.wakeful你爲我95%的方式出現。

就我個人而言,我想爲某個對象的每個api請求添加元數據,無論它是否分頁。我也想簡單地傳入一個手動定義的字典對象。

調整了自定義呈現

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 

父串行和查看示例

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

是否有可能使用此meta_dict傳遞來自視圖的值,我想通過meta_dict中的request.user – 2015-07-06 20:52:09