Django+IIS+Postgres环境下万级数据CSV导出条数与筛选结果不一致问题
问题根因排查
1. 代码逻辑错误(首要问题)
你当前的实现完全没有用到StreamingHttpResponse的流式特性:
- 代码中
filter_list = list(filter.values_list())会一次性把所有符合条件的记录全部加载到内存中,当数据量达到数万级别时,要么触发内存超限被进程杀掉,要么触发IIS的超时/响应大小限制,导致返回的数据被截断,最终表现为导出行数少于实际行数。 - 本地环境运行正常是因为本地没有IIS的各类限制,且测试时的网络环境更稳定。
2. IIS配置问题
IIS默认有多个限制会导致大响应被截断:
- 响应超时限制:默认IIS的FastCGI超时时间一般是90秒,大查询+全量加载数据的耗时很容易超过这个阈值,导致IIS直接中断连接。
- 响应大小限制:默认IIS的最大响应大小是30MB左右,数万条CSV记录很容易超过这个值,导致返回内容被截断。
修复方案
第一步:改写代码实现真正的流式导出
不要提前把QuerySet转为list,使用Django QuerySet的iterator()方法逐条加载数据,避免一次性占用大量内存:
import csv from django.http import StreamingHttpResponse from urllib.parse import urlsplit, parse_qs class Echo(object): """An object that implements just the write method of the file-like interface. """ def write(self, value): """Write the value by returning it, instead of storing in a buffer.""" return value def export_to_csv(request): # 先处理筛选逻辑 all_objects = DeviceVulns.objects.all() url = request.GET.get('filter_url') query = urlsplit(url).query params = dict(parse_qs(query)) params_dict = {k: v[0] for k, v in params.items()} filter_qs = DeviceVulnsFilter(params_dict, queryset=all_objects).qs.values_list( 'id', 'hostname', 'ip_address', 'os_name', 'vuln_title', 'cvss_score', 'vuln_found_date', 'is_exploitable', 'exploit_skill_level' ) # 定义生成器,先输出表头,再逐条输出数据 def row_generator(): # 输出表头 yield ['ID','Hostname', 'IP Address', 'OS_Name', 'Vuln Title','CVSS Score','Vuln Earliest Found Date On Asset','Vuln Exploitable?','Vuln Exploit Skill Level'] # 使用iterator逐条加载数据,避免全量加载到内存 for item in filter_qs.iterator(chunk_size=1000): yield [item[1], item[2], item[3], item[4], item[5], item[6], item[7], item[8]] pseudo_buffer = Echo() writer = csv.writer(pseudo_buffer) response = StreamingHttpResponse( (writer.writerow(row) for row in row_generator()), content_type="text/csv" ) response['Content-Disposition'] = 'attachment; filename="filtered-data.csv"' return response
第二步:调整IIS配置
- 调整FastCGI超时时间:打开IIS管理器 → 找到对应站点的FastCGI设置 → 将
activityTimeout和requestTimeout调整为600秒(可根据实际导出最大耗时调整) - 调整响应大小限制:打开IIS管理器 → 站点的「请求筛选」→ 「编辑功能设置」→ 将「允许的最大内容长度」调整为104857600(即100MB,可按需扩大)
- 关闭响应缓冲:IIS中对应站点的「输出缓存」→ 关闭动态内容缓存,避免IIS缓冲整个流式响应才返回。
第三步:数据库可选优化
800万条记录的表可以给常用的筛选字段加索引,降低筛选查询的耗时,进一步减少超时概率。
内容的提问来源于stack exchange,提问作者Gary Dorman
相关产品推荐
相关产品推荐

