Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to filter for multiple ids from a query param on a GET request with django rest framework?

I'm trying to make a web app API. I want to make an API request where multiple ids can be submitted.

The django rest framework tutorial shows how to get all records from a model. For example http://127.0.0.1:8000/snippets/ will return all snippet records. The tutorial also shows how to retrieve a single item from a model. http://127.0.0.1:8000/snippets/2/ will return only snippet record with pk=2.

I'd like to be able to request multiple records, but not all records.

How could I change this code so I could request multiple snippets?

snippets/urls.py

from django.conf.urls import url
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.snippet_list),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail),
]

snippets/views.py

def snippet_detail(request, *pk):
    try:
        snippet = Snippet.objects.filter(pk__in=pk)
    except Snippet.DoesNotExist:
        return HttpResponse(status=404)

    if request.method == 'GET':
        serializer = SnippetSerializer(snippet)
        return JSONResponse(serializer.data)
like image 233
cameron-f Avatar asked Sep 30 '15 21:09

cameron-f


2 Answers

I found this to work, following the Django REST Framework main tutorial and then documentation on Filtering against query parameters, adapting slightly. This allows a single url to return data from two GET requests: one returning objects whose ids match those given as a parameter, the other returning all objects, when no parameters are provided.

  • http://127.0.0.1:8000/snippets/ returns all snippets
  • http://127.0.0.1:8000/snippets/?ids=2,3,7 returns only snippets with id 2, 3 and 7

snippets/urls.py

from django.conf.urls import url
from snippets import views

urlpatterns = [
   .... (code for other urls here)
   url(r'^snippets/$', views.SnippetList.as_view(), name='snippet-list'),
   ....
]

snippets/views.py

.... 
from snippet.serializers import SnippetSerializer
....

class SnippetList(generics.ListCreateAPIView):
    serializer_class = SnippetSerializer

    def get_queryset(self):

        # Get URL parameter as a string, if exists 
        ids = self.request.query_params.get('ids', None)

        # Get snippets for ids if they exist
        if ids is not None:
            # Convert parameter string to list of integers
            ids = [ int(x) for x in ids.split(',') ]
            # Get objects for all parameter ids 
            queryset = Product.objects.filter(pk__in=ids)

        else:
            # Else no parameters, return all objects
            queryset = Product.objects.all()

        return queryset

snippets/serializers.py

....
class SnippetSerializer(serializers.ModelSerializer):

    class Meta:
        model = Snippet
        fields = ('url', 'id', 'title', 'code', 'linenos', 'language', 'style')
like image 52
harringr Avatar answered Sep 27 '22 21:09

harringr


Based in your comment, you could send the ids via url:

127.0.0.1:8000/snippets/?ids=2,3,4

and in your view

...
ids = request.GET.get('ids')  # u'2,3,4' <- this is unicode
ids = ids.split(',')  # [u'2',u'3',u'4'] <- this is a list of unicodes with ids values

Then you can query to Snippet model:

Snippet.objects.filter(pk__in=ids)

This could give you some problems if there's spaces between ids in url:

127.0.0.1:8000/snippets/?ids=2, 3 , 4

You could need process every value before perform a query

like image 44
Gocht Avatar answered Sep 27 '22 22:09

Gocht