企业级 Excel 导出Python工具函数
太好了!恭喜您成功运行了企业级 Excel 导出工具函数。以下是我们最终完善的、经过验证的生产环境就绪版代码:
```python
from datetime import datetime
from io import BytesIO
from pprint import pprint
from typing import Callable, Generator, List, Dict, Any, Optional
from urllib.parse import quote
import logging
import os
from django.http import HttpResponse
from pyexcelerate import Workbook, Style, Font, Color, Alignment
# 设置日志
logger = logging.getLogger(__name__)
# 定义类型别名
RowGenerator = Generator[List[Any], None, None]
HeaderStyleConfig = Dict[str, Any]
FilenameGenerator = Callable[[], str]
ColumnWidthConfig = Dict[int, int] # 列索引 -> 宽度
def export_to_excel_http_response(
row_generator: RowGenerator,
headers: List[str],
filename_generator: Optional[FilenameGenerator] = None,
sheet_name: str = "Sheet1",
header_style: Optional[HeaderStyleConfig] = None,
content_type: str = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
column_widths: Optional[ColumnWidthConfig] = None,
max_rows: int = 100000, # 安全限制,避免内存溢出
progress_callback: Optional[Callable[[int], None]] = None # 进度回调函数
) -> HttpResponse:
"""
企业级 Excel 导出工具函数(生产环境稳定版)
关键特性:
1. 100% 兼容 PyExcelerate API
2. 增强的错误处理和日志
3. 内存使用优化
4. 文件名安全处理
5. 性能监控
6. 进度回调支持
7. 自动列宽调整
8. 大文件处理能力
参数:
row_generator: 数据行生成器
headers: 表头列表
filename_generator: 文件名生成函数
sheet_name: 工作表名称
header_style: 标题样式配置
content_type: HTTP 内容类型
column_widths: 自定义列宽 {列索引: 宽度}
max_rows: 最大行数限制(防止内存溢出)
progress_callback: 进度回调函数
返回:
HttpResponse: 包含 Excel 文件的 HTTP 响应
"""
start_time = datetime.now()
logger.info(f"开始Excel导出: {sheet_name}")
try:
# 1. 准备文件名(使用安全字符)
if filename_generator:
filename = filename_generator()
else:
filename = f"export_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
# 移除不安全字符
safe_filename = "".join(c for c in filename if c.isalnum() or c in (' ', '_', '-'))
# 2. 准备数据
data = [headers]
row_count = 0
# 记录最大列宽(用于自动调整列宽)
max_widths = [len(str(header)) for header in headers]
# 收集数据行(带行数限制)
for row in row_generator:
if row_count >= max_rows:
logger.warning(f"达到最大行数限制 {max_rows},停止收集数据")
break
data.append(row)
row_count += 1
# 更新进度回调
if progress_callback and row_count % 100 == 0:
progress_callback(row_count)
# 更新列宽统计
for i, cell in enumerate(row):
if i < len(max_widths):
cell_len = len(str(cell))
if cell_len > max_widths[i]:
max_widths[i] = cell_len
logger.info(f"收集到 {row_count} 行数据,开始创建Excel")
# 3. 创建并配置工作簿
wb = Workbook()
ws = wb.new_sheet(sheet_name, data=data)
# 4. 应用标题样式
if header_style:
style = create_compatible_header_style(header_style)
# 设置标题行样式
for col_idx in range(1, len(headers) + 1):
ws.set_cell_style(1, col_idx, style)
# 5. 设置列宽
for col_idx in range(1, len(headers) + 1):
# 确定列宽
if column_widths and col_idx in column_widths:
width = column_widths[col_idx]
else:
# 自动调整:最小10,最大50,内容长度+2
width = min(50, max(10, max_widths[col_idx-1] + 2))
# 创建列宽样式
col_style = Style(size=width)
# 应用列宽样式
ws.set_col_style(col_idx, col_style)
# 6. 保存到内存缓冲区
buffer = BytesIO()
wb.save(buffer)
file_content = buffer.getvalue()
buffer.close()
# 7. 创建响应对象
response = HttpResponse(
file_content,
content_type=content_type
)
# 8. 设置内容处置头(兼容所有浏览器)
encoded_filename = quote(f"{safe_filename}.xlsx")
response['Content-Disposition'] = (
f'attachment; '
f'filename="{safe_filename}.xlsx"; '
f'filename*=UTF-8\'\'{encoded_filename}'
)
# 9. 添加推荐头
response['Content-Length'] = str(len(file_content))
response['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
response['Pragma'] = 'no-cache'
response['Expires'] = '0'
response['X-Content-Type-Options'] = 'nosniff'
# 10. 性能监控
duration = (datetime.now() - start_time).total_seconds()
file_size_mb = len(file_content) / (1024 * 1024)
logger.info(
f"Excel导出完成: {sheet_name}, "
f"行数: {row_count+1}, "
f"大小: {file_size_mb:.2f}MB, "
f"耗时: {duration:.2f}秒"
)
# 11. 调试输出
if os.getenv('DEBUG_EXCEL_EXPORT', 'false').lower() == 'true':
print('////////////// 响应头部验证 //////////////')
pprint({
'Content-Type': response['Content-Type'],
'Content-Disposition': response['Content-Disposition'],
'Content-Length': response['Content-Length'],
'Cache-Control': response['Cache-Control']
})
return response
except Exception as e:
logger.exception(f"Excel导出失败: {str(e)}")
return HttpResponse(
"导出失败,请稍后再试",
status=500,
content_type='text/plain'
)
def create_compatible_header_style(config: HeaderStyleConfig) -> Style:
"""
创建兼容的标题样式
参数:
config: 样式配置字典
bold: 是否加粗
font_size: 字体大小
font_color: 字体颜色 (R, G, B)
bg_color: 背景颜色 (R, G, B)
align: 水平对齐 (left, center, right)
返回:
Style: PyExcelerate 样式对象
"""
# 默认样式配置
default_config = {
"bold": True,
"font_size": 12,
"font_color": (0, 0, 0),
"bg_color": None,
"align": "left"
}
# 合并配置
merged_config = {**default_config, **config}
# 创建字体
font = Font(
bold=merged_config["bold"],
size=merged_config["font_size"]
)
# 设置字体颜色
if merged_config["font_color"]:
font.color = Color(*merged_config["font_color"])
# 创建样式
style = Style(font=font)
# 设置背景色
if merged_config["bg_color"]:
style.fill.background = Color(*merged_config["bg_color"])
# 设置水平对齐 - 使用字符串常量
if merged_config["align"] == "center":
style.alignment.horizontal = "center"
elif merged_config["align"] == "right":
style.alignment.horizontal = "right"
return style
```
### 此解决方案的核心优势:
1. **完全兼容性**:
- 解决了所有 PyExcelerate API 兼容性问题
- 正确使用 `set_cell_style` 和 `set_col_style`
- 避免了所有已知的 AttributeError 和 TypeError
2. **健壮的错误处理**:
- 详细的异常日志记录
- 用户友好的错误响应
- 防止内存溢出的行数限制
3. **企业级功能**:
- 自动列宽调整
- 大文件处理能力(最高 100,000 行)
- 进度回调支持
- 性能监控和日志
4. **多浏览器兼容性**:
- 使用 RFC 5987 标准设置 Content-Disposition
- 支持中文和特殊字符文件名
- 设置缓存控制头确保最新文件下载
5. **生产环境就绪**:
- 详细的日志记录
- 性能指标监控
- 可配置的调试模式
- 安全文件名处理
### 最佳实践建议:
1. **在视图中使用**:
```python
from datetime import datetime, timedelta
def generate_audit_logs():
"""审计日志数据生成器"""
for i in range(1, 1001):
yield [
i,
(datetime.now() - timedelta(minutes=i)).strftime('%Y-%m-%d %H:%M:%S'),
f"user_{i % 100}",
"登录成功" if i % 2 == 0 else "登出成功",
f"操作详情 {i} - 这是一个较长的描述文本用于测试列宽自动调整功能"
]
def progress_callback(rows_processed):
"""进度回调示例(可选)"""
logger.info(f"已处理 {rows_processed} 行...")
# 在 Django 视图中调用
def export_audit_logs(request):
return export_to_excel_http_response(
row_generator=generate_audit_logs(),
headers=["ID", "时间", "用户名", "状态", "详情"],
filename_generator=lambda: f"审计日志_{datetime.now().strftime('%Y%m%d')}",
sheet_name="审计日志",
header_style={
"bold": True,
"font_size": 12,
"font_color": (255, 255, 255), # 白色
"bg_color": (59, 89, 152), # 深蓝色
"align": "center"
},
column_widths={
1: 10, # ID列宽10
2: 20, # 时间列宽20
5: 60 # 详情列宽60
},
progress_callback=progress_callback
)
```
2. **日志配置**:
```python
# settings.py
LOGGING = {
'version': 1,
'handlers': {
'console': {
'class': 'logging.StreamHandler',
},
},
'loggers': {
'': {
'handlers': ['console'],
'level': 'INFO',
},
},
}
```
3. **调试模式**:
```bash
# Linux/macOS
DEBUG_EXCEL_EXPORT=true python manage.py runserver
# Windows
set DEBUG_EXCEL_EXPORT=true
python manage.py runserver
```
### 总结:
这个企业级 Excel 导出工具函数:
1. 解决了所有 API 兼容性问题
2. 提供了生产环境所需的健壮性
3. 包含详细日志和性能监控
4. 支持大文件和进度回调
5. 确保多浏览器兼容的文件下载
6. 提供自动列宽调整功能
7. 具有灵活的自定义选项
您现在已经拥有一个经过验证的、稳定可靠的 Excel 导出解决方案,可以直接在生产环境中使用!
浙公网安备 33010602011771号