eagleye

以下是一个企业级的 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 导出需求。

posted on 2025-07-31 12:58  GoGrid  阅读(9)  评论(0)    收藏  举报

导航