以下是一个企业级的 Excel 导出工具函数设计,采用模块化、可配置的方式实现高性能导出:
以下是一个企业级的 Excel 导出工具函数设计,采用模块化、可配置的方式实现高性能导出:
```python
from django.http import HttpResponse
from datetime import datetime
from typing import Callable, Generator, List, Dict, Any, Optional
from pyexcelerate import Workbook, Style, Font, Color
# 定义类型别名以提高可读性
RowGenerator = Generator[List[Any], None, None]
HeaderStyleConfig = Dict[str, Any]
FilenameGenerator = Callable[[], str]
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'
) -> HttpResponse:
"""
企业级 Excel 导出工具函数
参数:
row_generator (RowGenerator): 数据行生成器函数
headers (List[str]): 表头列表
filename_generator (FilenameGenerator, optional): 文件名生成函数
sheet_name (str, optional): 工作表名称,默认为"Sheet1"
header_style (HeaderStyleConfig, optional): 标题样式配置
content_type (str, optional): HTTP 内容类型,默认为 Excel 类型
返回:
HttpResponse: 包含 Excel 文件的 HTTP 响应
示例:
def data_generator():
yield [1, "2023-01-01", "user1", "login", "登录成功"]
yield [2, "2023-01-02", "user2", "logout", "登出成功"]
response = export_to_excel_http_response(
row_generator=data_generator(),
headers=["ID", "时间", "用户名", "事件类型", "详情"],
filename_generator=lambda: f"audit_logs_{datetime.now().strftime('%Y%m%d_%H%M%S')}",
header_style={"bold": True, "font_color": (0, 0, 0)}
)
"""
# 创建 HTTP 响应
response = HttpResponse(content_type=content_type)
# 生成文件名
if filename_generator:
filename = filename_generator()
else:
filename = f"export_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
response['Content-Disposition'] = f'attachment; filename="{filename}.xlsx"'
# 准备数据
data = [headers]
# 添加数据行
for row in row_generator:
data.append(row)
# 创建 Workbook
wb = Workbook()
ws = wb.new_sheet(sheet_name, data=data)
# 应用标题样式
if header_style:
style = create_header_style(header_style)
for col in range(1, len(headers) + 1):
ws.set_cell_style(1, col, style)
# 保存到响应
wb.save(response)
return response
def create_header_style(config: HeaderStyleConfig) -> Style:
"""
创建标题样式
参数:
config (HeaderStyleConfig): 样式配置字典
返回:
Style: PyExcelerate 样式对象
配置选项:
bold (bool): 是否加粗,默认 True
font_size (int): 字体大小,默认 12
font_color (tuple): 字体颜色 (R, G, B),默认 (0, 0, 0) 黑色
bg_color (tuple): 背景颜色 (R, G, B),默认 None
"""
# 默认样式配置
default_config = {
"bold": True,
"font_size": 12,
"font_color": (0, 0, 0),
"bg_color": None
}
# 合并配置
merged_config = {**default_config, **config}
# 创建字体
font = Font(
bold=merged_config["bold"],
size=merged_config["font_size"],
color=Color(*merged_config["font_color"])
)
# 创建样式
style = Style(font=font)
# 添加背景色
if merged_config["bg_color"]:
style.fill.background = Color(*merged_config["bg_color"])
return style
# 示例使用
def export_audit_logs_excel(view, queryset):
"""审计日志导出函数"""
# 准备表头
headers = ['ID', '时间戳', '用户名', '事件类型代码', '事件类型', 'IP地址', '用户代理', '详情']
event_types_dict = dict(AUDIT_EVENT_TYPES)
# 创建数据生成器
def row_generator():
for event in queryset.iterator(chunk_size=5000):
yield [
event.id,
event.timestamp.astimezone().strftime("%Y-%m-%d %H:%M:%S"),
event.username,
event.event_type,
event_types_dict.get(event.event_type, ''),
event.ip_address,
event.user_agent,
event.details
]
# 文件名生成器(使用北京时间)
def filename_generator():
now = timezone.now()
beijing_time = now + timedelta(hours=8)
return f"audit_logs_export_{beijing_time.strftime('%Y%m%d_%H%M%S')}"
# 标题样式配置
header_style = {
"bold": True,
"font_size": 12,
"font_color": (0, 0, 0), # 黑色
"bg_color": (200, 200, 200) # 浅灰色背景
}
# 调用导出函数
return export_to_excel_http_response(
row_generator=row_generator(),
headers=headers,
filename_generator=filename_generator,
sheet_name="安全审计日志",
header_style=header_style
)
```
### 设计特点与优势:
1. **模块化设计**:
- 核心导出功能 (`export_to_excel_http_response`)
- 样式创建功能 (`create_header_style`)
- 业务逻辑分离 (`export_audit_logs_excel`)
2. **高性能处理**:
```python
# 使用生成器避免内存溢出
def row_generator():
for event in queryset.iterator(chunk_size=5000):
yield [/* 数据行 */]
```
3. **灵活配置**:
```python
# 可配置的标题样式
header_style = {
"bold": True,
"font_size": 12,
"font_color": (0, 0, 0),
"bg_color": (200, 200, 200)
}
```
4. **时区处理**:
```python
# 北京时间文件名
def filename_generator():
now = timezone.now()
beijing_time = now + timedelta(hours=8)
return f"audit_logs_export_{beijing_time.strftime('%Y%m%d_%H%M%S')}"
```
5. **类型安全**:
```python
# 使用类型别名提高可读性
RowGenerator = Generator[List[Any], None, None]
HeaderStyleConfig = Dict[str, Any]
```
6. **企业级错误处理**(扩展):
```python
try:
wb.save(response)
except Exception as e:
logger.error(f"Excel导出失败: {str(e)}")
# 返回错误响应
return HttpResponseServerError("导出文件创建失败")
```
### 使用示例:
在 Django View 中调用:
```python
from .excel_export import export_audit_logs_excel
class AuditLogViewSet(viewsets.ModelViewSet):
# ...
@action(detail=False, methods=['post'])
def export(self, request):
# 获取查询集
queryset = self.filter_queryset(self.get_queryset())
# 使用导出函数
return export_audit_logs_excel(self, queryset)
```
### 高级扩展功能:
1. **多工作表支持**:
```python
def export_to_excel_http_response(
sheets: List[Dict[str, Any]],
# ...其他参数...
):
for sheet in sheets:
ws = wb.new_sheet(sheet['name'], data=sheet['data'])
if sheet.get('header_style'):
style = create_header_style(sheet['header_style'])
for col in range(1, len(sheet['headers']) + 1):
ws.set_cell_style(1, col, style)
```
2. **自动列宽调整**:
```python
def auto_adjust_column_width(ws, data):
col_widths = [0] * len(data[0])
for row in data:
for i, cell in enumerate(row):
width = len(str(cell)) + 2 # 加2个字符作为边距
if width > col_widths[i]:
col_widths[i] = width
for i, width in enumerate(col_widths):
ws.set_col_width(i+1, width)
```
3. **条件格式化**:
```python
def add_conditional_formatting(ws, config):
for rule in config:
# 示例:为特定值添加背景色
if rule['type'] == 'value':
for row_idx in range(2, ws.num_rows + 1):
cell_value = ws.get_cell_value(row_idx, rule['column'])
if cell_value == rule['value']:
ws.set_cell_style(
row_idx,
rule['column'],
Style(fill=Background(color=Color(*rule['color'])))
)
```
4. **进度回调**(适用于大型数据集):
```python
def row_generator(queryset, progress_callback=None):
total = queryset.count()
for i, event in enumerate(queryset.iterator(), 1):
if progress_callback and i % 100 == 0:
progress_callback(i, total)
yield [/* 数据行 */]
```
这个设计提供了高度可配置、可重用且高性能的 Excel 导出解决方案,特别适合企业级应用中的大数据量导出场景。通过分离关注点,核心导出函数可以复用于系统中的任何 Excel 导出需求。