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.
[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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With