0

I've an API endpoint to fetch all the items added by a user, it returns a JSONArray of all the objects added by a user.

curl 127.0.0.1:8000/api/products/ -H "Authorization: Token xxxxxxxxx"

The response looks something like this:

[{"url":"http://127.0.0.1:8000/api/products/18/","item_name":"ABC","barcode":"","item_price":5,"usr":"http://127.0.0.1:8000/auth/users/73/"},
{"url":"http://127.0.0.1:8000/api/products/19/","item_name":"PQR","barcode":"123456","item_price":85,"usr":"http://127.0.0.1:8000/auth/users/73/"},...]

Now, I want to retrieve only those objects with barcode value 123456, i.e object with 'item_name:PQR'. Hence, I tried using the 'WHERE' clause in curl as follows:

curl 127.0.0.1:8000/api/products?barcode=123456 -H "Authorization: Token xxxxxxxxx"

I'm getting a 301 response and not the appropriate object. As far as I know, response codes in the range 3xx implies multiple responses with a choice to choose one. What's the workaround to fix this issue? Expected output:

[{"url":"http://127.0.0.1:8000/api/products/19/","item_name":"PQR","barcode":"123456","item_price":85,"usr":"http://127.0.0.1:8000/auth/users/73/"}]
(or)
{"url":"http://127.0.0.1:8000/api/products/19/","item_name":"PQR","barcode":"123456","item_price":85,"usr":"http://127.0.0.1:8000/auth/users/73/"}

My model view set for the endpoint:
class ProductViewSet(viewsets.ModelViewSet):

    permission_classes = (IsAuthenticated,)
    queryset = ProductModel.objects.all()
    serializer_class = ProductSerializer

    def get_queryset(self):

        user = self.request.user
        queryset = super().get_queryset()
        queryset = queryset.filter(usr=user)
        return queryset

Thanks in advance.

Prajwal Kulkarni
  • 1,480
  • 13
  • 22

1 Answers1

1

The HTTP 301 status is a Moved Permanently redirect status response code.

Your url probably ends with a slash('/') and you have not added that in request. Django has a settings named APPEND_SLASH which is True by default if you have CommonMiddleware in the list of middleware in settings. This setting redirects your request to the slash appended url which in your case will be like so:

curl 127.0.0.1:8000/api/products/?barcode=123456 -H "Authorization: Token xxxxxxxxx"

That's the reason you're getting a 301. Try it with appended slash in url.

For the WHERE clause in your REST API, you've to make sure that you've added filters in the REST API that you've built. You can filter the queryset in the get_queryset method of your view by checking the query params passed, OR, you can use filters provided by REST framework if you're using DRF.

If you're using DRF, you can filter the queryset by adding/updating this method in your view:

def get_queryset(self):
    user = self.request.user
    queryset = super().get_queryset()
    barcode = self.request.query_params.get('barcode', None)
    if barcode:
        queryset = queryset.filter(barcode=barcode)
    queryset = queryset.filter(usr=user)
    return queryset

OR

def get_queryset(self):
    filters = {}
    filters['user'] = self.request.user
    queryset = super().get_queryset()
    barcode = self.request.query_params.get('barcode', None)
    if barcode:
        filters['barcode'] = barcode
    queryset = queryset.filter(**filters)
    return queryset

Both the querysets work the same way though.

Or you can use filters in your view by adding these to your view:

from django_filters.rest_framework import DjangoFilterBackend

class ProductViewSet(viewsets.ModelViewSet):

    permission_classes = (IsAuthenticated,)
    queryset = ProductModel.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['barcode', ]

    def get_queryset(self):

        user = self.request.user
        queryset = super().get_queryset()
        queryset = queryset.filter(usr=user)
        return queryset

References:

Mehak
  • 961
  • 9
  • 20
  • Hello there, Initially I tried with an appended '/' in the URL, in that case, the whole JSONArray was fetched, i.e, the array was not filtered to fetch only that object whose barcode value was supposed to be 123456. Any other workaround to fix this issue? – Prajwal Kulkarni Aug 10 '20 at 18:29
  • 1
    Yes for that you've to make sure that you've added filters in the REST API that you've built. You can filter the queryset in the `get_queryset` method of your view by checking the query params passed, OR, you can use filters provided by REST framework if you're using DRF. – Mehak Aug 10 '20 at 18:31
  • 1
    Can you clarify if you're using DRF or something else and post the code for your view so that I can help you with that and update the answer – Mehak Aug 10 '20 at 18:35
  • Kindly check my updated answer if it answers your query, You can also refer to DRF filtering documentation for further help. – Mehak Aug 10 '20 at 18:42
  • I'm sorry, but doesn't this return an array of all the objects irrespective of whether it belongs to the authenticated user or not? My objective is to fetch an object with a certain barcode from a set of objects of an authenticated user and not from all the objects in the database. Hence the need for token. A SQL query for the same would look something like this ```SELECT * from PRODUCTS WHERE user=authUser AND barcode=123456``` – Prajwal Kulkarni Aug 10 '20 at 18:54
  • I've updated the answer again after reading your whole views code. You can use any one method from above 3, it should work now. – Mehak Aug 10 '20 at 19:02
  • 1
    Yep, works just fine now. Thanks for sparing your time to make the appropriate changes. – Prajwal Kulkarni Aug 10 '20 at 19:05
  • hello, I've got another issue and no working answers so far, could you please look into it and suggest fixes? https://stackoverflow.com/questions/63808093/django-login-not-redirecting-to-index – Prajwal Kulkarni Sep 09 '20 at 13:56