探索 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

最后

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

相关推荐
失败尽常态52312 分钟前
用Python实现Excel数据同步到飞书文档
python·excel·飞书
2501_9044477414 分钟前
OPPO发布新型折叠屏手机 起售价8999
python·智能手机·django·virtualenv·pygame
青龙小码农14 分钟前
yum报错:bash: /usr/bin/yum: /usr/bin/python: 坏的解释器:没有那个文件或目录
开发语言·python·bash·liunx
大数据追光猿20 分钟前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
Leuanghing43 分钟前
【Leetcode】11. 盛最多水的容器
python·算法·leetcode
bing_1581 小时前
简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用
spring boot·后端·简单工厂模式
天上掉下来个程小白2 小时前
案例-14.文件上传-简介
数据库·spring boot·后端·mybatis·状态模式
xinxiyinhe2 小时前
如何设置Cursor中.cursorrules文件
人工智能·python
诸神缄默不语2 小时前
如何用Python 3自动打开exe程序
python·os·subprocess·python 3
Asthenia04123 小时前
基于Jackson注解的JSON工具封装与Redis集成实战
后端