Skip to main content
 首页 » 编程设计

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

2024年10月25日38pengyingh

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

People.objects.all()[0:5] 

或者,让它们按名称排序:

People.objects.order_by(name)[0:5] 

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

People.objects.order_by(name).filter(age__gt=65)[0:5] 

事实上,我能想到的唯一在查询集上没有函数的事件是有限的。

我想知道的是,是否有一种方法(内部的、文档化的或其他方式)可以在充当限制或切片的 QuerySet 上调用? 如果不是,执行此操作的最佳方法是什么?


注意事项:

  • 是的,这可能是个坏主意,不,我不太热衷于实现它,但如果有一个很好的理由来完成它,可以吗?
  • 是的,我知道切片是延迟执行的,这不是我要问的。
  • This is not a duplicate of this question ,正如公认的答案所说:

    Do results[:max_count] in a view, after .order_by().

请您参考如下方法:

查看 Django Querysets, its not as blackboxy 的代码看起来

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] 

关键行在这里:

qs.query.set_limits(start, stop) 

slice 是惰性的原因是因为它只接受 start 和 stop 值并将它们传递给另一个方法。

Which corresponds to a call to the sql.Query object here:

def set_limits(self, low=None, high=None): 

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

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()