Return dictionary instead of array in REST framewo

2019-04-29 15:54发布

问题:

I am converting a set of existing APIs from tastypie to REST framework. By default when doing list APIs, tastypie returns a dictionary containing the list of objects and a dictionary of metadata, where REST framework just returns an array of objects. For example, I have a model called Site. Tastypie returns a dictionary that looks like

{
  "meta": 
    { ... some data here ...}, 
  "site": 
    [
      {... first site...}, 
      {...second site...}
      ...
    ]
}

where REST framework returns just the array

[
  {... first site...}, 
  {...second site...}
  ...
]

We are not using the metadata from tastypie in any way. What is the least invasive way to change the return value in REST framework? I could override list(), but I would rather have REST framework do its thing where ever possible.

回答1:

I think you will have to override the list() method.

We first get the original response. Then we set the custom representation on response using data attribute and return response with this custom representation.

class MyModelViewSet(viewsets.ModelViewSet):

    def list(self, request, *args, **kwargs):
        response = super(MyModelViewSet, self).list(request, *args, **kwargs) # call the original 'list'
        response.data = {"site": response.data} # customize the response data
        return response # return response with this custom representation


回答2:

You can explore using DjangoRestMultipleModels Plugin

If you have meta from one model and site from another model you can do

from drf_multiple_model.views import MultipleModelAPIView

class SiteAPIListView(MultipleModelAPIView):
    queryList = [
        (Meta.objects.all(),MetaSerializer),
        (Site.objects.filter(meta='some_specific_meta'),SiteSerializer),
    ....
]

This would return exactly what you want

{
  "meta": 
    { ... some data here ...}, 
  "site": 
    [
      {... first site...}, 
      {...second site...}
      ...
    ]
}

Hope this helps from avoiding unnecessary glue code. Mainly the library allows you to combine many serializers and/or models into a single API call. Which is not available in django rest framework out of the box. But this can be used in your case as well, even if both results are coming from same model, by using different querysets for same model with different serializers. Or combination of both. It provides immense flexibility wrt, all permutations of models and serializers.



回答3:

I had the same issue. I have found that the most non-intrusive method is to handle this via a specialised pagination class, which does just that: response packing.

Have a look over the CustomPagination implementation: http://www.django-rest-framework.org/api-guide/pagination/#custom-pagination-styles