I am fairly new to Django rest framework and I had a couple questions that would really clear up a lot of stuff for me.
I was looking at docs for simple CRUD generic views like ListAPIView, Retrieve... etc.
For my list view I created it like this:
class CourseListApiView(ListAPIView):
queryset = Course.objects.all()
serializer_class = CourseListSerializer
Which makes sense because of the queryset returns Course.objects.all() so all the courses appear.
What I am not clear about is how the queryset in RetrieveApi works
class CourseRetrieveAPIView(RetrieveAPIView):
queryset = Course.objects.all()
serializer_class = CourseRetrieveSerializer
This is my retrieve view, it takes pk from my link and returns a corresponding course. What is unclear to me is why the queryset is Course.objects.all(), not a filtered query that gets the kwargs from the URL and filters my Courses. I tried it my way and got the same results, my view was:
class CourseRetrieveAPIView(RetrieveAPIView):
serializer_class = CourseRetrieveSerializer
def get_queryset(self):
queryset = Course.objects.filter(pk=self.kwargs.get('pk'))
return queryset
This makes more sense since the queryset is Course.objects.filter(pk=self.kwargs.get('pk')) instead of Course.objects.all() which to me doesn't make sense since I am filtering my courses by the pk in the URL
Hope my question made sense. Leave a comment if you need any clarification. I know the answer will be pretty obvious but I am very new to the framework
You will have to go through the codebase of rest_framework
. A function named get_object
uses two class variables named lookup_field
and lookup_url_kwarg
which have a default value of pk
and None
respectively.
Excerpt from the GenericAPIView
in rest_framework/generics.py
def get_object(self):
"""
Returns the object the view is displaying.
You may want to override this if you need to provide non-standard
queryset lookups. Eg if objects are referenced using multiple
keyword arguments in the url conf.
"""
queryset = self.filter_queryset(self.get_queryset())
# Perform the lookup filtering.
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
assert lookup_url_kwarg in self.kwargs, (
'Expected view %s to be called with a URL keyword argument '
'named "%s". Fix your URL conf, or set the `.lookup_field` '
'attribute on the view correctly.' %
(self.__class__.__name__, lookup_url_kwarg)
)
filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
obj = get_object_or_404(queryset, **filter_kwargs)
# May raise a permission denied
self.check_object_permissions(self.request, obj)
return obj
As you can see the lookup_url_kwarg
is set to be equal to lookup_field
if nothing is specified. If you change this value to a field of your requirement then the filter in get_object_or_404
changes.
Now coming back to your issue, when you are specifying the filter manually with url kwargs
you are not using the functionality provided by the RetrieveAPIView
. Instead what you are doing is filtering out your result with pk
from url kwargs
in get_queryset
and then sending that QuerySet result to get_object
which will again do the same thing for you.
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