8

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.

4
  • What is the expected output? Commented Oct 23, 2015 at 15:35
  • 1
    Tastypie version is the expected output, it is the one we have already. But we don't care about the metadata. Commented Oct 23, 2015 at 15:37
  • Have you tried using one of the paginators provided by the rest framework? It does return results in a dictionary format. It can also be customized to return results in the way you want - by overriding the get_paginated_response method. django-rest-framework.org/api-guide/pagination Commented Oct 23, 2015 at 16:11
  • @AbhinavI - It will give you the results but I fear what if he wants the results paginated as well. I wont suggest him to hack pagination to use it for purposes other than pagination. There are simpler and more elegant solutions around for this problem. Check mine and Rahul's answer as examples. Commented Oct 23, 2015 at 20:29

4 Answers 4

7

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
Sign up to request clarification or add additional context in comments.

2 Comments

I have mentioned this solution in my post. But what happens when REST framework changes the implementation of list()? I don't want to copy/paste a bunch of code from the original library and hope for the best. Can I somehow call the original list() and manipulate the response data?
Yes, you can do that. You can get the original response by calling super() and then modify response's data. Then you can return this modified response. Also, one could have thought of overriding to_representation() in the serializer but one can't do this as a ListSerializer is used in case of list requests and to_representation will be called each time for every instance. So, there we can have control of each instance representation but not the complete representation of instances.
0

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.

Comments

0

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

Comments

0

if you get single data in array format then user .get method instead of .filter method

.get

instead of

.filter

for get single data response only

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.