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
    )

 

三,测试效果:

image

 

posted @ 2026-08-02 22:30  刘宏缔的架构森林  阅读(25)  评论(0)    收藏  举报