fastapi: 把数据表导出成excel电子表格文件
一,安装第三方库
$ pip install pandas
第二个库:
$ pip install openpyxl
二,代码
javascript
function get_selected_id() {
// 1. 获取你的 form 元素 (假设 form 的 id 是 'myForm')
const form = document.getElementById('myForm');
console.log("form:", form)
// 2. 找到该 form 下所有选中的 checkbox
const checkedBoxes = form.querySelectorAll('input[type="checkbox"][name="check-item"]:checked');
console.log("checkedBoxes:", checkedBoxes)
// 3. 将 NodeList 转换为数组,并提取 value
const values = Array.from(checkedBoxes).map(checkbox => checkbox.value);
console.log(values); // 输出类似: ["apple", "banana"]
return values;
}
//导出角色列表
function role_export(){
var url = "{{ url_for('role_export') }}";
var ids = get_selected_id();
idstr = ''
for(let i = 0; i < ids.length; i++) {
console.log(ids[i]);
if (idstr == '') {
idstr = ids[i]
} else {
idstr = idstr+","+ids[i]
}
}
var dest_url = url+"?ids="+idstr
window.location.href = dest_url;
}
python:
# 做validator的form
class RoleExportForm(WTForm):
#id = IntegerField('page', [validators.NumberRange(min=1)], default=0)
# ,validators=[DataRequired()], min_entries=1
ids = FieldList(IntegerField("ids",validators=[NumberRange(min=1,message="每个数字最小不能小于 1")]),min_entries=1)
def validate_ids(self, field):
# field.data 是一个列表,包含了所有提交上来的数据
# 过滤掉 None 或空值,计算真正有效的条目数
valid_entries = [v for v in field.data if v is not None]
# 如果有效条目数小于 min_entries (这里是 1)
if len(valid_entries) < 1:
raise ValidationError("至少需要填写一项id!") # 这里写你自定义的报错信息
@router.get("/export",summary="角色数据导出")
async def role_export(request: Request,response: Response,db: AsyncSession = Depends(get_db)):
# 得到参数
get_data = request.query_params
print("get_data:", get_data)
# form_data_dict = MultiDict()
res = {}
ids = []
for key in get_data.keys():
print("key:", key)
# 用 .getlist(key) 把前端 append 的同名数组全部捞出来
if key == 'ids':
idsstr = get_data.get(key)
idslist = idsstr.split(',')
for value in idslist:
print("value:", value)
ids.append(int(value))
res["ids"] = ids
form = RoleExportForm(data=res)
if form.validate() == False:
error_str = get_error_message(form.errors)
return ApiResponse.fail(response=response, code=400, status_code=400, message=error_str)
# 查询数据
raw_data = []
for id in form.ids.data:
print("id:", id)
# 1. 查询用户是否存在
stmt = select(Role).where(Role.id == id)
result = await db.execute(stmt)
role = result.scalars().first()
if not role:
continue
raw_one = {
'id': role.id,
'name': role.name,
}
raw_data.append(raw_one)
# 2. 将数据转为 Pandas 的 DataFrame,并映射表头为中文
df = pd.DataFrame(raw_data)
df.rename(columns={
"id": "角色ID",
"name": "角色名字",
}, inplace=True)
# 3. 创建内存中的字节流对象(关键:避免写入服务器硬盘)
buffer = io.BytesIO()
# 4. 使用 ExcelWriter 将 DataFrame 写入这个内存 buffer
# index=False 表示不需要把 Pandas 默认的 0,1,2 行索引导出去
with pd.ExcelWriter(buffer, engine='openpyxl') as writer:
df.to_excel(writer, index=False, sheet_name="员工薪酬表")
# 5. 将指针移到 buffer 的起始位置,以便从头读取数据
buffer.seek(0)
# 6. 设置特殊的响应头,通知浏览器这是一个需要下载的文件附带文件名
# 使用 URL 编码防止中文文件名变成乱码
from urllib.parse import quote
filename = quote("角色数据表.xlsx")
headers = {
'Content-Disposition': f'attachment; filename="{filename}"; filename*=utf-8\'\'{filename}'
}
# 7. 通过 StreamingResponse 返回二进制流,指定 Excel 的 media_type
return StreamingResponse(
buffer,
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers=headers
)
三,测试效果:

浙公网安备 33010602011771号