推荐
关注
TOP
Message

Pymongo结合Sanic 导出excel

前言

在Sanic项目中集成MongoDB直接使用官方的异步驱动motor配合Sanic来操作MongoDB数据库。
项目介绍

从mongodb里读出数据 导成excel 反馈给前端

安装

pip install motor

链接句柄

链接

@app.listener('before_server_start')
async def setup_db(app, loop):
    app.ctx.client = AsyncIOMotorClient('mongodb://localhost:27017')

关闭

@app.listener('after_server_stop')
async def close_db(app, loop):
    app.ctx.client.close()

如上文
将client 挂载给了 app.ctx 避免了 多次初始化。

excel 导出代码

# 创建一个新的 Excel 工作簿
wb = Workbook()

# 选择活动的工作表,默认是第一个
ws = wb.active
ws.title = 'Sheet1'

# 将数据转换为列表形式,便于写入 Excel
rows = [list(record.values()) for record in list_data]

# 写入表头(假设数据的第一条记录的键即为表头)
headers = list(list_data[0].keys())
ws.append(headers)

# 写入数据
for row in rows:
  ws.append(row)

# 保存 Excel 文件到内存中的二进制流
with BytesIO() as output:
  wb.save(output)
  excel_data = output.getvalue()

# 设置响应头并发送 XLSX 文件内容
headers = {
  'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8',
  'Content-Disposition': f'attachment; filename={urllib.parse.quote(collection_name)}.xlsx'
}
return response.raw(excel_data, headers=headers)

如上文 list_data 是[{},{},{}] 这样的形式。

完整代码

import urllib
from io import BytesIO

from sanic import Sanic, response
from pymongo import MongoClient
from openpyxl import Workbook
from sanic_jinja2 import SanicJinja2
from motor.motor_asyncio import AsyncIOMotorClient

app = Sanic(__name__)
jinja = SanicJinja2(app)
app.config.JINJA2_TEMPLATE_DIR = './templates'


# 连接MongoDB
@app.listener('before_server_start')
async def setup_db(app, loop):
    app.ctx.client = AsyncIOMotorClient('mongodb://localhost:27017')


# 连接到 MongoDB
async def get_mongo_data(collection_name):
    db = app.ctx.client['xxx']
    collection = db.get_collection(collection_name)

    # 查询数据并返回
    async def fetch_data():
        cursor = collection.find({}, {'_id': 0})
        data = []
        async for record in cursor:
            data.append(dict(record))
        return data

    result = await fetch_data()
    return result


# 定义一个路由来渲染包含按钮的 HTML 页面
@app.route('/')
async def index(request):
    db = app.ctx.client['京东']
    collection_names = await db.list_collection_names()
    return jinja.render('index.html', request, collection_names=sorted(collection_names))


@app.route('/export')
async def export_data(request):
    collection_name = request.args.get('collection_name')  # 从查询参数中获取集合名
    if not collection_name:
        return response.json({"error": "Missing required parameter 'collection_name'"}, status=400)

    mongo_data = await get_mongo_data(collection_name)

    # 创建一个新的 Excel 工作簿
    wb = Workbook()

    # 选择活动的工作表,默认是第一个
    ws = wb.active
    ws.title = 'Sheet1'

    # 将数据转换为列表形式,便于写入 Excel
    rows = [list(record.values()) for record in mongo_data]

    # 写入表头(假设数据的第一条记录的键即为表头)
    headers = list(mongo_data[0].keys())
    ws.append(headers)

    # 写入数据
    for row in rows:
        ws.append(row)

    # 保存 Excel 文件到内存中的二进制流
    with BytesIO() as output:
        wb.save(output)
        excel_data = output.getvalue()

    # 设置响应头并发送 XLSX 文件内容
    headers = {
        'Content-Type': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=utf-8',
        'Content-Disposition': f'attachment; filename={urllib.parse.quote(collection_name)}.xlsx'
    }
    return response.raw(excel_data, headers=headers)


# 在请求结束时关闭连接(可选,根据实际需求)
@app.listener('after_server_stop')
async def close_db(app, loop):
    app.ctx.client.close()


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8888)

前端代码暂不展示。

posted @ 2024-03-18 15:56  始識  阅读(29)  评论(0编辑  收藏  举报