限制来自 Django QuerySet 的结果数量,而不使用切片

6 python django

限制从 Django 查询集返回的结果集的方法是通过数组切片完成的。例如,要获取前 5 个人:

People.objects.all()[0:5]
Run Code Online (Sandbox Code Playgroud)

或者,要按名称订购它们:

People.objects.order_by(name)[0:5]
Run Code Online (Sandbox Code Playgroud)

或按姓名排序,但仅限 65 岁以上的人:

People.objects.order_by(name).filter(age__gt=65)[0:5]
Run Code Online (Sandbox Code Playgroud)

事实上,对于没有函数的查询集,我能想到的唯一活动是限制。

我想知道的是,是否有一种方法(内部的、文档化的或其他方式)可以在QuerySet作为限制或切片的 a上调用?如果没有,这样做的最佳方法是什么?


笔记:

  • 是的,这可能是个坏主意,不,我不是很热衷于实施它,但如果有充分的理由去做,可以吗?
  • 是的,我知道切片是懒惰地执行的,这不是我要问的。
  • 这不是这个问题的重复,正如接受的答案所说:

    不要results[:max_count]在视图中,后.order_by()

小智 4

回顾一下Django Querysets的代码,它并不像看起来那么黑盒

def __getitem__(self, k):
    """
    Retrieves an item or slice from the set of results.
    """

    # ... trimmed ...

    if isinstance(k, slice):
        qs = self._clone()
        if k.start is not None:
            start = int(k.start)
        else:
            start = None
        if k.stop is not None:
            stop = int(k.stop)
        else:
            stop = None
        qs.query.set_limits(start, stop)
        return list(qs)[::k.step] if k.step else qs

    qs = self._clone()
    qs.query.set_limits(k, k + 1)
    return list(qs)[0]
Run Code Online (Sandbox Code Playgroud)

关键行在这里:

qs.query.set_limits(start, stop)
Run Code Online (Sandbox Code Playgroud)

切片之所以是惰性的,是因为它只获取startstop值并将它们传递给另一个方法。

这对应于对 sql.Query 对象的调用:

def set_limits(self, low=None, high=None):
Run Code Online (Sandbox Code Playgroud)

因此可以(尽管可能不推荐)像这样对查询集进行切片:

people = People.objects.order_by(name).filter(age__gt=65) # unevaluated
people.query.set_limits(start, stop)  # still unevaluated
for person in people:  # now its evaluated
    person.do_the_thing()
Run Code Online (Sandbox Code Playgroud)

  • @PeterDeGlopper有时您想要限制查询中返回的内容,但仍然能够传递可以进一步过滤或操作的查询集实例。使用切片会导致“获取切片后无法过滤查询。” (2认同)