Skip to main content
 首页 » 编程设计

python之手动添加行到 StreamingHttpResponse (Django)

2025年05月04日36arxive

我正在使用 Django 的 StreamingHttpResponse 动态传输大型 CSV 文件。根据the docs ,迭代器被传递给响应的 streaming_content 参数:

import csv 
from django.http import StreamingHttpResponse 
 
def get_headers(): 
    return ['field1', 'field2', 'field3'] 
 
def get_data(item): 
    return { 
        'field1': item.field1, 
        'field2': item.field2, 
        'field3': item.field3, 
    } 
 
# StreamingHttpResponse requires a File-like class that has a 'write' method 
class Echo(object): 
    def write(self, value): 
        return value 
 
 
def get_response(queryset): 
    writer = csv.DictWriter(Echo(), fieldnames=get_headers()) 
    writer.writeheader() # this line does not work 
 
    response = StreamingHttpResponse( 
        # the iterator 
        streaming_content=(writer.writerow(get_data(item)) for item in queryset), 
        content_type='text/csv', 
    ) 
    response['Content-Disposition'] = 'attachment;filename=items.csv' 
 
    return response 

我的问题是:如何在 CSV 编写器上手动写入一行?手动调用 writer.writerow(data) 或 writer.writeheader()(也在内部调用 writerow())似乎不会写入数据集,而只有来自 streaming_content 的生成/流式数据写入输出数据集。

请您参考如下方法:

答案是使用生成器函数生成结果,而不是动态计算它们(在 StreamingHttpResponse 的 streaming_content 参数中)并使用我们创建的伪缓冲区(Echo 类)来写入一行响应:

import csv 
from django.http import StreamingHttpResponse 
 
def get_headers(): 
    return ['field1', 'field2', 'field3'] 
 
def get_data(item): 
    return { 
        'field1': item.field1, 
        'field2': item.field2, 
        'field3': item.field3, 
    } 
 
# StreamingHttpResponse requires a File-like class that has a 'write' method 
class Echo(object): 
    def write(self, value): 
        return value 
 
def iter_items(items, pseudo_buffer): 
    writer = csv.DictWriter(pseudo_buffer, fieldnames=get_headers()) 
    yield pseudo_buffer.write(get_headers()) 
 
    for item in items: 
        yield writer.writerow(get_data(item)) 
 
def get_response(queryset): 
    response = StreamingHttpResponse( 
        streaming_content=(iter_items(queryset, Echo())), 
        content_type='text/csv', 
    ) 
    response['Content-Disposition'] = 'attachment;filename=items.csv' 
    return response