Flask-Alchemy查询结果使用Pandas转为xlsx给Flask直接下载

465 阅读2分钟

背景介绍

标题有点绕…不过确实是这么回事:
Flask里面用Alchemy进行ORM数据映射后指定条件查询用户表>扔给Pandas实例化DataFrame对象>调用DataFrameto_excel()方法将转换的xlsx文件数据存放在内存中的一个BytesIO对象中>再生成response响应返回给浏览器

好吧,我觉得时间长了我怕自己都记不清当时是在干什么了,不嫌啰嗦~

具体步骤:

实例化一个io.BytesIO对象传给pandas.ExcelWriter用,实现将df.to_excel()方法输出的xlsx数据到内存中,然后再使用Flask的make_response生成一个response响应,并设置headers让浏览器解析为文件下载.

下面代码例子是在蓝图中实现的,其中usersFlask-SQLAlchemy部分进行的ORM映射取的查询.

import io

import pandas as pd
from flask import Blueprint, render_template, request, jsonify, make_response
from pandas import ExcelWriter

bp = Blueprint('admin', __name__, url_prefix='/admin')

@bp.route('/exportUser')
def export_user():
    """
    导出用户数据表为可下载的excel文件
    Returns:

    """
    # SQLAlchemy中的模型查询
    users = User.query.filter(User.role == 1)
    # 实例化字节类型IO对象,用来在内存中存储对象,不用在磁盘上生成临时文件了
    out = io.BytesIO()
    # 实例化输出xlsx的writer对象
    writer = ExcelWriter(out, engine='openpyxl')
    # 将SQLAlchemy模型的查询对象拆分SQL语句和连接属性传给pandas的read_sql方法
    df = pd.read_sql(users.statement, users.session.bind)
    # 简单数据切片,选择所有行,第六列到最后一列范围
    df = df.iloc[:, 5:]
    # 对df列名重命名
    df.rename(columns={
        'xm': '姓名',
        'sfzh': '身份证号',
        'csny': '出生年月',
        'xb': '性别',
        'bm': '部门',
        'zw': '职务',
        'jb': '级别',
        'vcode': '校验码'
    }, inplace=True)
    # 将df转excel保存在内存writer变量中,转换结果中不要包含index行号
    df.to_excel(writer, index=False)
    # 这一步不能漏了,不save的话浏览器下载的xls文件里面啥也没有
    writer.save()
    # 重置一下IO对象的指针到开头
    out.seek(0)
    # IO对象使用getvalue()可以返回二进制的原始数据,用来给要生成的response的data
    resp = make_response(out.getvalue())
    # 设置response的header,让浏览器解析为文件下载行为
    resp.headers['Content-Disposition'] = 'attachement; filename=users.xlsx'
    resp.headers['Content-Type'] = 'application/vnd.ms-excel; charset=utf-8'

    return resp

模板HTML中可以直接用<a href="/admin/exportUser">下载</a>点击浏览器就会弹出保存文件的效果.