【问题标题】:What's the difference returning a QuerySet or a list of it?返回 QuerySet 或它的列表有什么区别?
【发布时间】:2022-08-06 03:47:52
【问题描述】:

假设我有两个模型BookUser,在Book 上有一个外键。在我的一个 API 端点中,我返回以下 QuerySet:

return User.objects.get(pk=user_id).posts.all()

结果在浏览器上正确呈现。如果我将行更改为(使用列表):

return list(User.objects.get(pk=user_id).posts.all())

输出结果是一样的。

由于 QuerySet 是延迟加载(仅在评估时执行),我的问题是:

两种方法在内存或性能方面有什么区别?还是 return 和 list 具有相同的效果(评估 QuerySet)?我应该使用什么最好的方法?

我阅读了文档,但我不太清楚返回 QuerySet 或它的列表时会发生什么。

额外信息:我正在使用基于 FastAPI 的 Ninja API,但对于 django 视图的上下文数据,问题是相同的。

提前致谢!

  • 我的直觉是,在大多数情况下,性能几乎相同。您是否尝试对其进行基准测试?有任何明显的性能差异吗?
  • 我尝试过使用这个(装饰器)进行基准测试[github.com/goutomroy/django_select_prefetch_related/blob/master/….一个额外的数据库命中是使用列表进行的。
  • 如果总是使用 return,我认为性能不会有任何差异。基准测试是仅在返回查询集的方法上执行还是在该方法的用户上执行?

标签: python django orm django-queryset


【解决方案1】:

您可以通过应用更多过滤器从查询集中生成另一个查询集。

qs = User.objects.get(pk=user_id).posts.all()

...

qs = qs.exclude( topic='brexit') # this is now an ex-topic.

将列表处理成更短的列表需要更多的工作。如果进一步过滤涉及将关系跨越到您尚未预取其对象的其他表中,那么效率也很低。 (即 N+1 问题)。

您还可以使用 .union() 等扩展查询集。

另一方面,使用生成器函数将“带注释的”查询集馈送到模板上下文以关联相邻对象可能很有用。

def new_month_annotator( qs):
   month = '000000'
   for obj in qs.order_by('date')
       obj_month = obj.date.strftime('%Y%M')
       obj.new_month = (obj_month != month)
       yield obj
       month = obj_month

如果您在模板中对其进行迭代,您现在可以轻松地在 forloop 中生成月份标签。 (您可以同样轻松地对对象列表执行此操作,使用生成器或仅通过修改对象)。

【讨论】:

    猜你喜欢
    • 2015-02-27
    • 2020-02-01
    • 2020-05-02
    • 2011-12-24
    • 2011-09-29
    • 1970-01-01
    • 2019-10-08
    • 2011-09-30
    • 2012-03-22
    相关资源
    最近更新 更多