使用 get_queryset() 方法还是设置 queryset 变量?

69
这两段代码在第一眼看起来是相同的:
class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_poll_list'
    queryset = Poll.active.order_by('-pub_date')[:5]

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_poll_list'

    def get_queryset(self):
        return Poll.active.order_by('-pub_date')[:5]

它们之间有什么区别吗?如果有:

哪种方法更好?或者在设置queryset变量比覆盖get_queryset方法更好?反之亦然。

5个回答

103
在您的示例中,覆盖querysetget_queryset具有相同的效果。我稍微倾向于设置queryset,因为它更简洁。
当您设置queryset时,查询集仅在启动服务器时创建一次。另一方面,对于每个请求,都会调用get_queryset方法。
这意味着如果您想要动态调整查询,则get_queryset很有用。例如,您可以返回属于当前用户的对象:
class IndexView(generic.ListView):
    def get_queryset(self):
        """Returns Polls that belong to the current user"""
        return Poll.active.filter(user=self.request.user).order_by('-pub_date')[:5]

另一个可以使用get_queryset的例子是当你想要基于可调用函数进行过滤时,例如,返回今天的投票:

class IndexView(generic.ListView):
    def get_queryset(self):
        """Returns Polls that were created today"""
        return Poll.active.filter(pub_date=date.today())

如果您尝试通过设置queryset来做同样的事情,那么date.today()只会在视图加载时调用一次,而在一段时间后,视图将显示不正确的结果。
class IndexView(generic.ListView):
    # don't do this!
    queryset = Poll.active.filter(pub_date=date.today())

2
在编写代码时,可以在 get_queryset 方法中使用 self.model.objects.filter(...)。如果继承自己的列表视图,则应该记住要引用 super(YourListViewExtendingSomeOtherLV, self).get_queryset().filter(...) - andilabs

14
其他答案忽略了 queryset 属性在进程启动时被评估的重要含义。因为你不仅仅是创建一个 queryset,而且实际上正在对其进行切片,查询将在那一点上被执行。这意味着你只会在那个时刻获取前5个调查,即使创建了另一个调查,它们也不会刷新,直到进程重新启动。
这正是你应该使用 get_queryset() 的时候。

3
根据文档所述,对未评估的查询集进行切片操作不会使其被评估,除非您使用切片语法中的“step”参数。 - Alasdair
1
这不是真的,如果你向数据库中插入了一个新的最近条目,它将会出现。我刚刚测试过了,你可以自己试试。如果查询集被限制为例如到timezone.now(),那么当程序启动时之后就永远不会获得任何结果了(除非程序重新启动)。查询在请求时运行,但是查询中的任何条件(例如timezone.now())都不会重新计算,而是保持初始值。 - run_the_race

4

查询集属性是内部使用的,总是使用方法(您经常需要执行基于请求或会话变量的自定义查询,例如)


3

模型和 queryset 很相似,但是如果提供了 queryset 的值,则会覆盖模型的值。

模型是此视图显示的对象类型。

通过重写 get_queryset,可以控制此视图显示的 特定实例(例如,创建的最后 5 个实例)。

Django 文档中的说明:

model:

此视图将显示其数据的模型。指定 model = Foo 实际上相当于指定 queryset = Foo.objects.all(),其中 objects 代表 Foo 的默认管理器。

queryset:

表示对象的 QuerySet。 如果提供,queryset 的值将取代 model 提供的值

get_queryset:

get_queryset() 返回用于检索此视图将显示的对象的 queryset。默认情况下,如果设置了 queryset 属性,则 get_queryset() 将返回其值;否则,它将通过调用 model 属性的默认管理器上的 all() 方法来构建一个 QuerySet。


0

在类中只需包含

Class MyViewSet(GenericAPIView):

    queryset = ''

如果您在任何地方都不使用查询集,则可以这样做。
这对我有用。
谢谢。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接