探索 SQLAlchemy 中的数据库反射技术

前言

最近进行接口自动化框架优化时,总感觉直接写sql语句影响代码的美感,所以决定使用SQLAlchemy。但是有一个麻烦的地方, 就是需要手动定义表结构,这样就比较费时了,一个表都有几十个字段,手动定义显然不可行,投入产出比低。庆幸的是,SQLAlchemy提供了 反射技术,它使得 SQLAlchemy 能够在不提前定义表结构的情况下,直接从数据库中动态读取表结构并映射为Python对象。趁着这个机会正好 总结一下SQLAlchemy 反射技术。笔者采用的2.0版本。

自动映射

自动映射方法(automap_base() 和 prepare())更为简便和自动化,适用于不需要手动管理表对象的场景,适合于快速构建基于现有数据库的应用程序。

使用自动映射反射数据库

为了反射数据库,这里使用automap_base,使用automap_base创建一个Base对象,

ini 复制代码
from sqlalchemy.ext.automap import automap_base

Base = automap_base()

然后,需要将一个引擎连接到想反射的数据库,初始化引擎,

ini 复制代码
from sqlalchemy import create_engine

DATABASE_URL = f"mysql+pymysql://root:127.0.0.1:3306/pangxiaolu"
engine = create_engine(DATABASE_URL)

这样,就做好了反射数据库的准备工作:Base和引擎创建。

接下来,调用创建的Base对象的prepare方法,将扫描我们刚刚创建的引擎上的所有可用内容,并反射它所能反射的所有内容。

ini 复制代码
Base.prepare(autoload_with=engine)

只需要这一行代码,就完成了整个数据库的映射工作。这个反射已经为每个表创建了ORM对象。我们输出测试一下,

python 复制代码
for k, v in Base.classes.items():
    print(f"{k}: {v}")
    break

输出结果如下,

vbnet 复制代码
user: <class 'sqlalchemy.ext.automap.user'>

当然,我们也可以这样访问映射的类,比如有一个表user

bash 复制代码
User = Base.classes.user
print(User)  # <class 'sqlalchemy.ext.automap.user'>
print(type(User))  # <class 'sqlalchemy.orm.decl_api.DeclarativeMeta'>

接下来,使用映射的类,就简单了

ini 复制代码
from sqlalchemy.orm import Session

session = Session(bind=engine)
user = session.query(User).first()

注意:有些参数将被废弃,如果你是这样写的Base.prepare(engine, reflect=True) ,会发生警告,下面是官方文档介绍

vbnet 复制代码
engine --

legacy; use AutomapBase.autoload_with. Used to indicate the Engine or Connection with which to reflect tables with, if AutomapBase.reflect is True.

Deprecated since version 1.4: The AutomapBase.prepare.engine parameter is deprecated and will be removed in a future release. Please use the AutomapBase.prepare.autoload_with parameter.

reflect --

legacy; use AutomapBase.autoload_with. Indicates that MetaData.reflect() should be invoked.

Deprecated since version 1.4: The AutomapBase.prepare.reflect parameter is deprecated and will be removed in a future release. Reflection is enabled when AutomapBase.prepare.autoload_with is passed.

可以看到这两参数后面将会被删除。

反射

反射单个表

我们需要创建元数据对象,

css 复制代码
from sqlalchemy import create_engine, MetaData, Table

metadata = MetaData()

同样,需要初始化引擎,

ini 复制代码
DATABASE_URL = f"mysql+pymysql://root:127.0.0.1:3306/pangxiaolu"
engine = create_engine(DATABASE_URL)

创建好元数据和引擎之后,就有了反射一个表所需要的一切,进行反射

ini 复制代码
user = Table('user', metadata, autoload_with=engine)

autoload_with=engine:这是Table类的一个关键字参数,它告诉SQLAlchemy自动从数据库中加载user表的结构信息。autoload_with参数需要一个数据库引擎(engine)的实例作为值。

好了,我们来测试一下

scss 复制代码
print(user.columns.keys())  # ['id', 'name', 'gender', 'area_code', 'mobile']

反射整个数据库

为了反射整个数据库,可以使用 metadata 对象的 reflect 方法。 reflect 方法会扫描引擎上的所有可用内容,并反射它所能反射的所有内容。

ini 复制代码
metadata.reflect(bind=engine)

使用反射表,

ini 复制代码
user = metadata.tables['user']

接下来使用就一样了。

反射原理

  1. 创建数据库引擎(Engine)
  2. 加载元数据:使用元数据(MetaData)对象来加载数据库的结构信息。
  3. 反射数据库结构:调用 MetaData 对象的 reflect() 方法
  4. 映射到类:Table对象被创建,使用反射得到的Table对象,SQLAlchemy可以自动创建或更新Python类,这些类映射到数据库表。这个过程称为ORM映射。

看自动映射的源码,发现也是调用MetaData 对象的 reflect() 方法,核心源码如下

ini 复制代码
if reflect:
           assert autoload_with
           opts = dict(
               schema=schema,
               extend_existing=True,
               autoload_replace=False,
           )
           if reflection_options:
               opts.update(reflection_options)
           cls.metadata.reflect(autoload_with, **opts)  # type: ignore[arg-type]  # noqa: E501

最后

好了,基本用法目前可以满足我做接口自动化,更多高级用法工作中用到再继续延伸吧,也可以查看官方文档介绍。

相关推荐
IT毕设梦工厂1 小时前
计算机毕业设计选题推荐-在线拍卖系统-Java/Python项目实战
java·spring boot·python·django·毕业设计·源码·课程设计
luthane1 小时前
python 实现average mean平均数算法
开发语言·python·算法
码农研究僧2 小时前
Flask 实现用户登录功能的完整示例:前端与后端整合(附Demo)
python·flask·用户登录
Ylucius2 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
凡人的AI工具箱2 小时前
AI教你学Python 第11天 : 局部变量与全局变量
开发语言·人工智能·后端·python
sleP4o2 小时前
Python操作MySQL
开发语言·python·mysql
是店小二呀2 小时前
【C++】C++ STL探索:Priority Queue与仿函数的深入解析
开发语言·c++·后端
canonical_entropy2 小时前
金蝶云苍穹的Extension与Nop平台的Delta的区别
后端·低代码·架构
凌不了云2 小时前
windows环境下安装python第三方包
开发语言·python
大熊程序猿2 小时前
python 读取excel数据存储到mysql
数据库·python·mysql