FastAPI 操作数据库

文章目录

    原本想使用 python orator 这个 ORM 方案。
    但是发现搜索 FastAPI ORM 的方案,并没有人提到 orator。
    我主要是担心第一次使用 FastAPI 这个异步框架,再配合上 orator 这类异常小众的 ORM,会不会踩坑。

    所以,还是优先使用官方推荐的方案。至于是不是 ORM,不重要。

    encode/databases

    FastAPI 官方文档里推荐的异步操作数据库的方案是 encode/databases。

    参考:

    https://fastapi.tiangolo.com/advanced/async-sql-databases/

    不过里面的示例代码都是 databases 配合 SQLAlchemy 使用,我觉得 SQLAlchemy 的学习成本过高,
    非常不值得。用 RAW 足够满足我目前的简单需求。

    Raw queries 的使用方式可以参考 databases 的官方文档:

    https://www.encode.io/databases/database_queries/

    安装 databases 依赖

    pip install databases
    

    可以看到,在安装 databases 时,自动安装了 SQLAlchemy 依赖。。。

    由于我用的是 MySQL 数据库,这里需要再安装 MySQL driver。

    pip install databases[mysql]
    

    数据库连接的建立与断开

    # Use a connection pool of between 5-20 connections.
    # database = Database('mysql://localhost/example?min_size=5&max_size=20')
    database = databases.Database('mysql://user:password@localhost:3306/db')
    
    
    @app.on_event("startup")
    async def startup():
        await database.connect()
    
    
    @app.on_event("shutdown")
    async def shutdown():
        await database.disconnect()
    

    数据库连接池

    这个默认的连接数是多少?我看 SQLAlchemy 默认是 5 个,但是不知道 databases 的默认值是多少。

    数据库配置参数从 .env 文件读取

    由于我的主站是用 laravel 写的,所以数据库的配置都是放在 laravel 项目的 .env 配置文件中,
    为了避免存在多份配置文件,所以需要能够从 FastAPI 读取其他目录下的 .env 文件。

    https://fastapi.tiangolo.com/advanced/settings/#reading-a-env-file

    创建软链接的方式,将 laravel 项目的 .env 文件链接过来,然后 FastAPI 在当前目录读取是否可行。

    .env snippet 统一设置 key 的名称。

    如果未来还有其他配置项,实在不行,就复制一份到当前目录下,也未尝不可。
    然后参考 laravel 的做法,不降 .env 放入 git 代码管理,存在一份 .env.example 模板就行了。

    处理数据库连接异常

    主要是为了方便本地调试,在没有测试数据,或者本地没有数据库的情况下,依然可以调试界面及基本功能。

    @app.on_event("startup")
    async def startup():
        try:
            await database.connect()
        except Exception as e:
            logger.info("fail to connect db")
            logger.info("type error: " + str(e))
    

    至于数据库读取的相关功能,我目前的项目直接在线上服务器调试也未尝不可。

    读取数据

    async def get_app_info(name):
        query = "SELECT * FROM kv WHERE `key` = :name"
        result = await database.fetch_one(query=query, values={"name": name})
        logger.info(result)
        # TODO
        # 判断记录不存在的情况,新建一条记录,方便后台编辑
        return result
    

    参考

    • https://www.encode.io/databases/

    关于作者 🌱

    我是来自山东烟台的一名开发者,有感兴趣的话题,或者软件开发需求,欢迎加微信 zhongwei 聊聊,或者关注我的个人公众号“大象工具”, 查看更多联系方式