Search code examples
django-rest-frameworkdjango-urlsurl-parameters

Django Rest sending param in url to queryset


I was looking for answer in related topics, but none was working. So following Django Rest Guid about filtering I wanted to add posibility to filter data via url.

I have my view:

class ArtistList(generics.ListAPIView):
    serializer_class = ArtistSerializer

    def get_queryset(self):
        queryset = Artist.objects.all()
        name = self.request.query_params.get('name', None)
        print(name)
        if name is not None:
            queryset = queryset.filter(name=name)
        return queryset

and my urls file:

urlpatterns = [
...
path('artists/<str:name>', ArtistList.as_view(), name='artists'),    

]

When I provide url like: http://localhost:8000/artists?name=A5 it's showing that this url doesn't exist. I also was trying http://localhost:8000/artists/A5 which lead to returning all artists instead of only 1.

I also was trying re_path('^artists/(?P<name>.+)/$', ArtistList.as_view(), name='artists'), like in the example in guide, but I still was getting an error. What is wrong here?

I have also second question. What is the best way to manipulate urls with params? I mean should I declare first url for returning all object and second for only specifc one?


Solution

  • You are mixing up two things:

    1. you have the path which is the part often the host and before the querystring, the querystring starts with ?, so the path for http://localhost:8000/artists?name=A5 is artists. The URL parameters are placed in self.kwargs; and

    2. you have the querystring the querystring is a key-value pair collection that starts after the question mark, these items are stored in request.query_params.

    If you thus want to filter with /artists/A5, then you work with:

    # http://localhost:8000/artists/A5
    
    class ArtistList(generics.ListAPIView):
        serializer_class = ArtistSerializer
    
        def get_queryset(self):
            return Artist.objects.filter(name=self.kwargs['name'])

    In that case you always need to provide a name, since not providing one will, as you found out, return a HTTP 404 response.

    If you want to use the querystring, you change the path to:

    # http://localhost:8000/artists?name=A5
    
    urlpatterns = [
        # …,
        path('artists/', ArtistList.as_view(), name='artists'),    
    ]

    and then you use self.query_params like you already did. In that case the name=… part is not required.