Django Rest Framework: Defining a view's queryset, why hit the DB at startup

Viewed 18

The DRF View docs have this example:

from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser

class UserList(generics.ListCreateAPIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    permission_classes = [IsAdminUser]

From reading the Django Docs, whenever .all() is encountered, it hits the database. This means I suspect the DB is being hit when the view id being created, which seems not ideal to me.

The source code at least shows that it revaluates the queryset, so its not just using the cached versoin when instantiated:

    assert self.queryset is not None, (
        "'%s' should either include a `queryset` attribute, "
        "or override the `get_queryset()` method."
        % self.__class__.__name__
    )

    queryset = self.queryset
    if isinstance(queryset, QuerySet):
        # Ensure queryset is re-evaluated on each request.
        queryset = queryset.all()
    return queryset

My question is, wouldn't it be better to set the queryset in their example as follows:

class UserList(generics.ListCreateAPIView):
    queryset = User.objects  # <--- i.e. drop the .all()
    ...

This way it doesnt hit the DB at start up.

1 Answers

Django doesn't make DB call when you define queryset. DB will be called only when queryset is used. See details here.

You can check it by this code:

from django.db import connection
print(len(connection.queries)) # total count of query calls, return 0
queryset = User.objects.all()
print(len(connection.queries)) # return 0
len(queryset) # only here we actually use queryset and send DB call
print(len(connection.queries)) # return 1

So you can use your initial code, it doesn't make any additional DB calls.

Related