You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Django、DRF中通过POST请求生成CSV并返回流式响应的正确方法

通过POST请求实现Django流式CSV下载的正确方法

你的代码无法返回文件响应,主要有三个问题:Content-Disposition头格式错误、CSV内容生成不规范、DRF渲染器干扰。以下是修正方案:

关键问题分析

  1. Content-Disposition头转义错误:原代码用"包裹文件名,这是HTML转义字符,HTTP响应头中直接使用双引号即可,否则浏览器无法识别附件类型。
  2. CSV内容生成不规范:手动拼接行无法处理字段含逗号、引号等特殊字符的情况,容易导致CSV格式损坏。
  3. DRF渲染器干扰:api_view默认使用JSON渲染器,可能会修改流式响应的头信息或内容。

修正后的完整代码

方案一:使用csv模块生成规范流式内容+自定义CSV渲染器

import csv
from io import StringIO
from django.http import StreamingHttpResponse
from rest_framework.decorators import api_view, renderer_classes
from rest_framework.renderers import BaseRenderer

# 自定义CSV渲染器,让DRF正确识别响应类型
class CSVRenderer(BaseRenderer):
    media_type = 'text/csv'
    format = 'csv'

def generate_csv_data():
    # 用csv.writer处理特殊字符,生成标准CSV
    output = StringIO()
    writer = csv.writer(output)
    
    # 写入表头和数据
    writer.writerow(['Name', 'Email'])
    writer.writerow(['John Doe', 'john.doe@example.com'])
    writer.writerow(['Jane Smith', 'jane.smith@example.com'])
    
    # 分块读取并返回,实现流式输出
    output.seek(0)
    while True:
        chunk = output.read(1024)
        if not chunk:
            break
        yield chunk

@api_view(['POST'])
@renderer_classes([CSVRenderer])
def download_csv(request):
    response = StreamingHttpResponse(generate_csv_data(), content_type='text/csv')
    # 正确设置下载头,无需转义引号
    response['Content-Disposition'] = 'attachment; filename="data.csv"'
    return response

方案二:绕过DRF渲染器,直接返回原生响应

如果不需要自定义渲染器,也可以手动禁用DRF的渲染流程:

import csv
from io import StringIO
from django.http import StreamingHttpResponse
from rest_framework.decorators import api_view

def generate_csv_data():
    output = StringIO()
    writer = csv.writer(output)
    writer.writerow(['Name', 'Email'])
    writer.writerow(['John Doe', 'john.doe@example.com'])
    writer.writerow(['Jane Smith', 'jane.smith@example.com'])
    output.seek(0)
    return output.read()

@api_view(['POST'])
def download_csv(request):
    response = StreamingHttpResponse(generate_csv_data(), content_type='text/csv')
    response['Content-Disposition'] = 'attachment; filename="data.csv"'
    # 告诉DRF不要修改该响应
    response.accepted_renderer = None
    response.accepted_media_type = 'text/csv'
    response.renderer_context = {}
    return response

核心要点总结

  • 始终使用csv模块生成CSV内容,避免手动拼接导致的格式错误。
  • Content-Disposition头直接用attachment; filename="文件名.csv"格式,无需HTML转义。
  • 若使用DRF的api_view,需指定CSV渲染器或手动禁用DRF的渲染干扰,确保响应被浏览器识别为下载文件。

内容的提问来源于stack exchange,提问作者Digvijaysing Rajput

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:00:03