我正在处理超过500万个项目的查询集(对于批量ML目的)我需要拆分查询集(因此我可以执行多线程操作) 不评估查询集,因为我只需要访问一次查询集中的每个项目,因此我不想缓存评估原因的查询集项目。
是否可以将项目选择到一个查询集中并将其拆分而不进行评估?或者我将不得不通过使用Limits [:size]查询多个查询集来实现此行为?
NB:我知道可以使用Iterable循环查询集而不进行评估,但我的问题与如何拆分查询集(如果可能)然后运行可以在每个分割的查询集上进行迭代。
答案 0 :(得分:5)
Django提供了一些可帮助您管理分页数据的类 - 即分布在多个页面上的数据,带有“上一页/下一页”链接:
from django.core.paginator import Paginator
object_list = MyModel.objects.all()
paginator = Paginator(object_list, 10) # Show 10 objects per page, you can choose any other value
for i in paginator.page_range(): # A 1-based range iterator of page numbers, e.g. yielding [1, 2, 3, 4].
data = iter(paginator.get_page(i))
# use data
答案 1 :(得分:2)
将查询集传递给线程不是我建议的。我知道你要做的事情和原因,但最好只是将某种param设置传递给每个线程,然后让Thread执行部分查询。 通过这种方式,您的线程与调用代码不同。
另一方面,如果您尝试使用线程来解决由高数据库查询引起的滞后问题,您可能会发现使用事务管理是一种更好的路径。 这个链接link有一些有用的提示。我使用它而不是Threads
答案 2 :(得分:2)
如果您的Django版本为 1.11 或小于 1.10 , 1.9 之类的版本,请使用paginator.page(page_no),但注意,当发现无效/找不到页面时,这可能引发InvalidPage异常。
对于版本 <= 1.11 ,请使用以下代码:
from django.core.paginator import Paginator
qs = MyModel.objects.all()
paginator = Paginator(qs, 20)
for i in paginator.page_range:
current_page = paginator.page(i)
current_qs = current_page.object_list
如果您使用的是Django版本> = 2.0,请改用paginator.get_page(page_no),但也可以使用paginator.page(page_no)。
对于版本== 2.0,请使用以下代码:
from django.core.paginator import Paginator
qs = MyModel.objects.all()
paginator = Paginator(qs, 20)
for i in paginator.page_range:
current_page = paginator.get_page(i)
current_qs = current_page.object_list
根据django文档使用paginator.get_page(page_no)的优点如下:
返回有效页面,即使page参数不是数字或不是 在范围内。
对于paginator.page(page_no),如果page_no不是数字或超出范围,则必须手动处理异常。
答案 3 :(得分:1)
是的,您可以,从此gist
根据更新后的答案:
def queryset_iterator(queryset, chunk_size=1000):
"""
Iterate over a Django Queryset ordered by the primary key
This method loads a maximum of chunk_size (default: 1000) rows in it's
memory at the same time while django normally would load all rows in it's
memory. Using the iterator() method only causes it to not preload all the
classes.
Note that the implementation of the iterator does not support ordered query sets.
"""
try:
last_pk = queryset.order_by('-pk')[:1].get().pk
except ObjectDoesNotExist:
return
pk = 0
queryset = queryset.order_by('pk')
while pk < last_pk:
for row in queryset.filter(pk__gt=pk)[:chunk_size]:
pk = row.pk
yield row
gc.collect()