为什么当我将光标传递给StreamingHttpResponse时,它在生成器函数中关闭了?

2024-04-26 09:53:41 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个潜在的大查询集,我不想加载到内存中。这是一个自定义的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)

Tags: 函数内存sqlsizeifgeneratorcursorrows
1条回答
网友
1楼 · 发布于 2024-04-26 09:53:41

Why is the cursor closed in my generator function?

因为您使用return退出上下文管理器:

return StreamingHttpResponse(queryset_generator(cursor))

这将退出with块,触发上下文管理器上的__exit__方法,该方法关闭光标。with语句或上下文管理器无法知道您刚刚将对cursor对象的引用传递给其他仍需要它保持打开状态的对象。with不关心引用,只关心语义块结尾。在

如果需要在StreamingHttpResponse()实例完成流数据之前保持光标打开状态,则不能在return语句周围使用上下文管理器。在

传入游标,而不在上下文管理器中使用它,并使queryset_generator()函数负责使用with

^{pr2}$

以及

^{3}$

现在光标保持打开状态,直到queryset_generator()中的while循环完成。在

相关问题 更多 >