Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

adding metadata to filtering in django rest framework

I have a generic ListCreateAPIView view. I've implemented a get_queryset function that performs a search. The function parses the query, extract tags and terms and returns a query set.

def get_queryset(self):
        query = self.request.QUERY_PARAMS.get('query', None)

        # No deleted items
        queryset = Items.objects.filter(deleted__isnull=True)

        if query is None:
            return queryset

        predicates = []

        # Generate predicates from query       

        queryset = queryset.filter(reduce(__and__,predicates))
        return queryset

What is the best way to add metadata to the response with data from the get_queryset function ?

I'm looking for something similar to the way pagination works.

{
 query : {
     terms : ['term1','term2'], 
     tags  : ['tag1','tag2'] , 
    }
 results : [
      { name : 'item1', .... }
      { name : 'item2', .... }
   ]
}

EDIT

So i created a custom FilterBackend for the filtering and I now have an instance of the request and the response. Looking at the pagination code for django rest i see it's wrapping the results in serializer. The pagination is build into the view class so the fw invokes the serialization if a paginator is detected. Looking at the search api did not produce any new ideas.

My question remains, What is the best, and least intrusive way, of adding metadata from the filter backend to the response ?

One way i can think of (and one that i don't like) is to overload the matadata onto the request in the filter backend and override finalize_response in the view - without a doubt the worst way to do it.

like image 274
haki Avatar asked Apr 16 '14 13:04

haki


People also ask

What is metadata Django REST framework?

[The OPTIONS ] method allows a client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.

What is the difference between ModelSerializer and HyperlinkedModelSerializer?

The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.

What is DjangoFilterBackend?

The DjangoFilterBackend class is used to filter the queryset based on a specified set of fields. This backend class automatically creates a FilterSet (django_filters. rest_framework. FilterSet) class for the given fields. We can also create our own FilterSet class with customized settings.


1 Answers

I'm not sure it's the best way, but I would probably override get to simply intercept the response object and modify response.data however you wish. Something as simple as

from rest_framework import generics

class SomeModelList(generics.ListCreateAPIView):
    """
    API endpoint representing a list of some things.
    """

    model = SomeModel
    serializer_class = SomeModelSerializer

    def get(self, request, *args, **kwargs):
        response = super(SomeModelList, self).get(request, *args, **kwargs)

        # redefine response.data to include original query params
        response.data = {
            'query': dict(request.QUERY_PARAMS),
            'results': response.data
        }

        return response

If you found yourself repeating this for multiple list views you could keep yourself DRY using a Mixin and include it in your list API classes:

from rest_framework import generics
from rest_framework.mixins import ListModelMixin

class IncludeQueryListMixin(ListModelMixin):
    def list(self, request, *args, **kwargs):
        response = super(IncludeQueryListMixin, self).list(request, *args, **kwargs)

        # redefine response.data to include original query params
        response.data = {
            'query': dict(request.QUERY_PARAMS),
            'results': response.data
        }

        return response


class SomeModelList(IncludeQueryListMixin, generics.ListCreateAPIView):
    """
    API endpoint representing a list of some things.
    """

    model = SomeModel
    serializer_class = SomeModelSerializer
like image 66
Fiver Avatar answered Oct 26 '22 23:10

Fiver