| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 |
- """将行数据序列化为 Excel 字节流。"""
- from __future__ import annotations
- import json
- from io import BytesIO
- from typing import Iterable
- from urllib.parse import quote
- from openpyxl import Workbook
- from openpyxl.utils import get_column_letter
- def _cell_value(raw: object) -> object:
- if raw is None:
- return ""
- if isinstance(raw, (list, dict)):
- return json.dumps(raw, ensure_ascii=False)
- return raw
- def rows_to_excel_bytes(
- rows: Iterable[dict[str, object]],
- columns: list[tuple[str, str]],
- *,
- sheet_name: str = "Sheet1",
- ) -> bytes:
- workbook = Workbook()
- worksheet = workbook.active
- worksheet.title = sheet_name[:31]
- headers = [header for header, _ in columns]
- worksheet.append(headers)
- for row in rows:
- worksheet.append([_cell_value(row.get(field)) for _, field in columns])
- for index, (header, _) in enumerate(columns, start=1):
- column_letter = get_column_letter(index)
- max_len = len(header)
- for cell in worksheet[column_letter]:
- if cell.value is not None:
- max_len = max(max_len, len(str(cell.value)))
- worksheet.column_dimensions[column_letter].width = min(max_len + 2, 60)
- buffer = BytesIO()
- workbook.save(buffer)
- return buffer.getvalue()
- def build_content_disposition(filename: str) -> str:
- ascii_fallback = "export.xlsx"
- encoded = quote(filename, safe="")
- return f"attachment; filename=\"{ascii_fallback}\"; filename*=UTF-8''{encoded}"
|