21

djangoとdjango-rest-frameworkを使用して、すべてのjson応答にルート要素を追加するための最良の方法を決定しようとしています。

カスタムレンダラーを追加することが、私が達成したいことを達成するための最良の方法だと思います。これは、私がこれまでに思いついたものです。

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()です。

任意のポインタ/アドバイスをいただければ幸いです、

乾杯

4

2 に答える 2

14

後世のために、以下が最終的な解決策です。ページ化された結果も再フォーマットするようになったため、元の結果からわずかに大きくなりました。

また、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'
于 2013-02-14T22:30:00.297 に答える
5

そこまでの道のりの95%を私に与えてくれたever.wakefulの功績です。

個人的には、ページ付けされているかどうかに関係なく、特定のオブジェクトに対するすべてのAPIリクエストにメタデータを追加したかったのです。また、手動で定義したdictオブジェクトを単純に渡したいと思いました。

微調整されたカスタムレンダラー

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
于 2013-05-30T06:12:34.130 に答える