Django Admin的import_export插件在大表上OOM是因为默认将整张Excel一次性加载进内存解析为Python对象列表,10万行×50列可能占用2GB+内存,超出限制触发MemoryError或被系统终止,仅适合小数据场景。

为什么 Django Admin 的 import_export 插件在大表上会 OOM?
因为 django-import-export 默认把整张 Excel 加载进内存解析成 Python 对象列表,10 万行 × 50 列的 Excel 可能占用 2GB+ 内存,直接触发 MemoryError 或被系统 kill。它适合小数据(
用 openpyxl 流式读取 Excel(不加载全量内存)
关键不是“用什么库”,而是“怎么用”:避开 load_workbook() 全量加载,改用 openpyxl.load_workbook(filename, read_only=True) + 迭代器模式读取。
-
read_only=True启用只读流式解析,内存占用从 O(n) 降到 O(1)(仅当前行) - 必须用
worksheet.iter_rows(),不能用worksheet['A1:Z100000']这种切片写法(会强制加载全部) - 每行用
tuple(cell.value for cell in row)提取值,避免保留 cell 对象引用 - 示例片段:
wb = openpyxl.load_workbook(file_path, read_only=True) ws = wb.active for row in ws.iter_rows(min_row=2, values_only=True): # 跳过 header if not any(row): break # 空行提前退出 process_row(row) # 每行单独处理,比如 bulk_create 或分批入库 wb.close()
Django 中分批写入数据库(避免单事务撑爆 transaction log)
即使 Excel 读取不爆内存,一次性 Model.objects.bulk_create() 百万条仍可能卡住或失败——PostgreSQL 的 WAL 日志、MySQL 的 innodb_log_file_size 都有上限。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 按
batch_size=5000分批(不是越大越好;5000 是 PostgreSQL 和 MySQL 在多数配置下的安全阈值) - 每批后调用
transaction.commit()(如果手动控制事务),或确保不在一个大事务里 - 避免在循环里做模型验证(
full_clean()),先用 pandas 或自定义校验函数预筛脏数据 - 注意外键字段:若需关联已有数据,先用
dict(Model.objects.values_list('code', 'id'))构建映射表,别在循环里查库
导出大 Excel 时用 xlsxwriter 替代 openpyxl
openpyxl 导出时会构建完整 DOM 树,百万行极易 OOM;xlsxwriter 是纯写入流式引擎,边写边 flush,内存恒定。
立即学习“Python免费学习笔记(深入)”;
- 必须用
Workbook(filename, {'constant_memory': True})开启常驻内存模式 - 不能修改已写单元格,不能读取已写内容——这是流式代价,但正好符合导出场景
- 日期/数字类型需显式调用
workbook.add_format()设置格式,否则导出为纯文本 - 示例:
wb = xlsxwriter.Workbook(output_path, {'constant_memory': True}) ws = wb.add_worksheet() for i, row_data in enumerate(queryset_iterator): # 自己实现分页迭代器 ws.write_row(i, 0, row_data) wb.close()
真正卡点不在工具选型,而在「读取—校验—转换—写入」四步是否全程流式。任何一步把全量数据 hold 在内存里,大表就废了一半。

















