最近一直在用FastApi开发Web系统,经常需要遇到数据导出的需求。
分享一个我自己使用的导出函数。
优点:
1.以数据流生成并返回给前端下载,不占用服务器存储。
2.可以自定义表头和数据样式
代码里的注释都标记完整了,可以直接使用。
import xlwt
from io import BytesIO
from urllib.parse import quote
from fastapi.responses import StreamingResponse
def export_exl(header, data=None, data_col=None, file_name='download', need_order=False):
"""
以流的形式导出到excel
:param header: ['列名1', '列名2']
:param data: [{'a': 1, 'b': 2}] 数据集,与header、data_col对应
:param data_col: ['与列名对应的字段1', '与列名对应的字段2']
:param file_name: 文件名称
:param need_order: 是否插入序号
:return:
"""
def set_style():
"""
设置样式
:return:
"""
# 居中设置
alignment = xlwt.Alignment()
alignment.horz = xlwt.Alignment.HORZ_CENTER
alignment.vert = xlwt.Alignment.VERT_CENTER
alignment.wrap=1 #设置自动换行
# 设置表头字体样式
head_style = xlwt.XFStyle()
font = xlwt.Font()
font.name = 'Times New Roman' # 字体
font.height = 20 * 16 #字体大小
font.bold = True # 字体加粗
font.colour_index=9 #字体颜色
# 设置背景颜色
pattern = xlwt.Pattern()
# 设置背景颜色的模式
pattern.pattern = xlwt.Pattern.SOLID_PATTERN
# 背景颜色
pattern.pattern_fore_colour = 40
head_style.pattern=pattern
head_style.font = font # 设置字体
head_style.alignment = alignment # Add Alignment to Style
# 设置表中内容样式
cont_style = xlwt.XFStyle()
font = xlwt.Font()
font.name = 'Times New Roman' # 字体
font.bold = False # 字体加粗
cont_style.font = font # 设置字体
cont_style.alignment = alignment # Add Alignment to Style
# 设置单元格边界
borders = xlwt.Borders()
borders.left = xlwt.Borders.THIN
borders.right = xlwt.Borders.THIN
borders.top = xlwt.Borders.THIN
borders.bottom = xlwt.Borders.THIN
head_style.borders = borders
cont_style.borders = borders
return head_style, cont_style
def get_sheet(_book, _index):
"""
创建sheet页
:param _book:
:param _index:
:return:
"""
_name = "sheet_{}".format(str(_index))
_sheet = _book.add_sheet(_name)
return _sheet
def write_head(_head, _sheet, _head_style):
"""
写入表头
:param _head:
:param _sheet:
:param _head_style:
:return:
"""
for head in range(len(header)):
context = str(header[head])
# need_width = (1 + len(context)) * 256
need_width = 20 * 256
table_sheet.col(head).width = need_width
table_sheet.write(0, head, context, style=_head_style)
# 是否插入序号
if need_order:
header.insert(0, '序号')
sheet_index = 1
book = xlwt.Workbook(encoding='utf-8') # 创建 Excel 文件
table_sheet = get_sheet(book, sheet_index) # 添加sheet表
h_style, c_style = set_style()
write_head(header, table_sheet, h_style)
if data and data_col:
# 插入数据
row = 1
for item in data:
if need_order:
table_sheet.write(row, 0, row, style=c_style) # 写入序号
for col in range(len(header[1:])):
table_sheet.write(
row, col+1, str(item.get(data_col[col], '-') if item.get(data_col[col]) else '-'), style=c_style)
else:
for col in range(len(header)):
table_sheet.write(
row, col, str(item.get(data_col[col], '-') if item.get(data_col[col]) else '-'), style=c_style)
row += 1
if row > 50000: # 单表数量超过 65535 条 添加新的表
row = 1
sheet_index += 1
table_sheet = get_sheet(book, sheet_index) # 添加sheet表
write_head(header, table_sheet, h_style)
# print(help(table_sheet))
# table_sheet.data_validation("A1", {'validate': 'list', 'source': [1, 2, 3, 4]})
sio = BytesIO() # 返回文件流到浏览端下载,浏览端必须以form提交方式方能下载成功!
book.save(sio) # 这点很重要,传给save函数的不是保存文件名,而是一个StringIO流
sio.seek(0) # 保存流
# 组装header
headers = {"content-type": "application/vnd.ms-excel",
"content-disposition": f'attachment;filename={quote(file_name,"utf8")}.xlsx'}
# 以流的形式返回浏览器
return StreamingResponse(sio, media_type='xls/xlsx', headers=headers)
【注意】安装依赖:
pip install fastapi[all] xlwt