我有一个潜在的大查询集,我不想加载到内存中。这是一个自定义的SQL语句。在
django.http.StreamingHttpResponse
接受iterator
(生成器)参数。为了避免将所有内容加载到内存中,我使用了Postgres服务器端游标和fetchmany
(尽管我还没有验证这是否真的有效)。在
这是我传递的生成器函数:
def queryset_generator(cursor, chunk_size=CHUNK_SIZE):
while True:
if cursor.closed:
yield "cursor closed!"
break
rows = cursor.fetchmany(chunk_size)
if not rows:
break
yield rows
我测试游标是否是关闭的,否则当代码随后尝试访问一个关闭的游标时,psycopg2会抱怨。在
下面是我如何在视图中传递它(简化SQL):
^{pr2}$这让我始终如一地
cursor closed!
为什么在生成器函数中光标关闭?在我看来,如果我这样做,效果很好:
with connections['mydb'].cursor() as cursor:
cursor.execute("SELECT * FROM foobar;")
return StreamingHttpResponse(cursor.fetchall())
同样值得注意的是,这在shell中运行良好:
cursor = connections['mydb'].cursor()
cursor.execute(...)
for x in StreamingHttpResponse(queryset_generator(cursor))._iterator:
print(x)
因为您使用
return
退出上下文管理器:这将退出
with
块,触发上下文管理器上的__exit__
方法,该方法关闭光标。with
语句或上下文管理器无法知道您刚刚将对cursor
对象的引用传递给其他仍需要它保持打开状态的对象。with
不关心引用,只关心语义块结尾。在如果需要在
StreamingHttpResponse()
实例完成流数据之前保持光标打开状态,则不能在return
语句周围使用上下文管理器。在传入游标,而不在上下文管理器中使用它,并使
^{pr2}$queryset_generator()
函数负责使用with
:以及
^{3}$现在光标保持打开状态,直到
queryset_generator()
中的while
循环完成。在相关问题 更多 >
编程相关推荐