You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django Rest Framework视图QuerySet定义:为何启动时触发数据库查询?

关于DRF中queryset定义的疑问与分析

问题背景

DRF官方文档给出的示例视图如下:

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]

有人依据Django文档,担心调用.all()会在视图类创建时就触发数据库查询,觉得这种写法不够合理。查看DRF源码后发现,框架会在每次请求时重新评估QuerySet:

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

于是产生疑问:把示例中的queryset改成User.objects(移除.all())是否更优,以此避免启动时触发数据库查询?

解答

首先明确一个关键知识点:Django的QuerySet是惰性求值的。User.objects.all()只是创建了一个QuerySet对象,并不会立即执行数据库查询,只有当真正需要获取数据(比如序列化、迭代、调用len()等)时,SQL才会被执行。所以官方示例的写法根本不会在启动时触发查询,担心完全是多余的。

再看DRF的源码逻辑:框架在get_queryset()方法中,会先检查queryset是否是QuerySet实例,如果是,就调用.all()生成一个全新的QuerySet。这么做的目的是确保每次请求都拿到未被缓存的、全新的查询集合,避免复用之前请求的查询结果。

如果改成queryset = User.objects,这里的User.objects是Manager对象,不是QuerySet。此时源码中的isinstance(queryset, QuerySet)判断不成立,不会执行.all()。后续视图逻辑需要处理的是QuerySet,直接传入Manager会导致报错——因为Manager不支持分页、序列化等QuerySet才有的操作。

所以结论很明确:不能这么修改,官方示例的写法才是正确且规范的。

内容的提问来源于stack exchange,提问作者run_the_race

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 06:00:17