使用 get_queryset() 方法或设置查询集变量?

Posted

技术标签:

【中文标题】使用 get_queryset() 方法或设置查询集变量?【英文标题】:Use get_queryset() method or set queryset variable? 【发布时间】:2013-11-11 12:01:57 【问题描述】:

这两段代码乍一看是相同的:

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 方法时?反之亦然。

【问题讨论】:

【参考方案1】:

在您的示例中,覆盖 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())

【讨论】:

你也可以写get_querysetself.model.objects.filter(...)。在继承自己的列表视图的情况下,值得记住的是应该参考super(YourListViewExtendingSomeOtherLV, self).get_queryset().filter(...)【参考方案2】:

其他答案忽略了一个重要含义,即在进程启动时评估 queryset 属性这一事实。因为您不只是创建一个查询集,您实际上是在对其进行切片,此时查询将被求值。这意味着您此时只会获得前 5 名民意调查,即使您创建另一个民意调查,它们也不会刷新,直到流程重新启动。

这正是你应该使用get_queryset()的时候。

【讨论】:

根据the docs,切片未评估的查询集不会导致它被评估,除非您使用切片语法的'step'参数。 这不是真的,如果你在数据库中插入了一个新的最近条目,它就会出现。我刚刚测试过,自己测试一下。例如,如果查询集限制在 timezone.now() 之前,那么是的,在程序启动之后,您将永远不会得到任何结果(除非程序重新启动)。查询是根据请求运行的,但查询中的任何术语(例如 timezone.now() 都不会重新评估,而是初始值)。【参考方案3】:

queryset 属性在内部使用,始终使用方法(例如,您经常需要根据请求或会话变量执行自定义查询)

【讨论】:

【参考方案4】:

模型和查询集非常相似,但查询集的值(如果提供)会覆盖模型的值。

Model 是这个视图显示的对象类型。

覆盖 get_queryset 控制此视图显示的特定实例 (例如:最近创建的 5 个实例)

来自 Django 的文档:

型号:

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

查询集:

表示对象的 QuerySet。 如果提供,则 queryset 的值将取代为模型提供的值

get_queryset:

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

【讨论】:

【参考方案5】:

类内只包含

Class MyViewSet(GenericAPIView):

    queryset = ''

如果您不在任何地方使用查询集。

这对我有用。

谢谢

【讨论】:

以上是关于使用 get_queryset() 方法或设置查询集变量?的主要内容,如果未能解决你的问题,请参考以下文章

无法在没有 `.queryset` 属性或覆盖 `.get_queryset()` 方法的视图上应用 DjangoModelPermissions

如何在 Django 中覆盖“get_queryset()”

如何将值从 get_queryset() 传递到 get_context_data()

Django get_object ,get_queryset方法

Django-rest-framework多条件查询/分页/多表Json

Django ReadOnlyModelViewSet:get_querySet 被 pk 过滤