Reputation: 1894
According to Django REST framework documentation, the following two code snippets should behave identically.
class UserViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving users.
"""
def list(self, request):
queryset = User.objects.all()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
queryset = User.objects.all()
user = get_object_or_404(queryset, pk=pk)
serializer = UserSerializer(user)
return Response(serializer.data)
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset for viewing and editing user instances.
"""
serializer_class = UserSerializer
queryset = User.objects.all()
But the way I interpret it, in the first case the query User.objects.all()
is run with every api call, which in the second case, the query is run only once when the web server is started, since it's class variable. Am I wrong ? At least in my tests, trying to mock User.objects.all will fail, since the UserViewSet.queryset will already be an empty Queryset object by that time.
Someone please explain me why shouldn't the queryset class argument be avoided like pest and get_queryset be used instead ? Edit: replacing queryset with get_queryset makes self.queryset undefined in the retrieve method, so I need to use self.get_queryset() within the method as well...
Upvotes: 4
Views: 6799
Reputation: 90
Adding to Aliva's answer and quoting from DRF viewset code, under get_queryset()
method definition it states:
This method should always be used rather than accessing
self.queryset
directly, asself.queryset
gets evaluated only once, and those results are cached for all subsequent requests. You may want to override this if you need to provide different querysets depending on the incoming request.
Upvotes: 1
Reputation: 5720
from django docs:
QuerySets are lazy – the act of creating a QuerySet doesn’t involve any database activity. You can stack filters together all day long, and Django won’t actually run the query until the QuerySet is evaluated
ModelViewSet
provides other actions like delete
and update
you may need to add some limitations on them for user model (like checking permissions or maybe you don't like to let users simply delete their profiles)
self.queryset
is used for router and basename and stuff, you can ignore it and set basename in your router manually. it's not forced but I think it make my code more readable
note that usually def get_queryset
is used when you want to do some actions on default queryset for example limit self.queryset
based on current user. so if get_queryset
is going to return .objects.all()
or .objects.filter(active=True)
I suggest using self.queryset
to have a cleaner code
note2: if you decide to define get_queryset
I suggest to also define self.queryset
(if possible)
note3: always use self.get_queryset
in your view method, even you didn't defined this method, you may need need to create that method later and if your view method are using self.queryset
it may cause some issues in your code
Upvotes: 7