SqlAlchemy 2.0 中文文档(七十八)(4)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
云数据库 RDS PostgreSQL,高可用系列 2核4GB
简介: SqlAlchemy 2.0 中文文档(七十八)

SqlAlchemy 2.0 中文文档(七十八)(3)https://developer.aliyun.com/article/1560963


新的核心功能

完全可扩展,类型级别的核心操作符支持

到目前为止,核心从未有过任何系统来为列和其他表达式构造添加对新 SQL 运算符的支持,除了ColumnOperators.op()方法,这个方法“刚好”能让事情正常运行。此外,核心从未有过任何系统允许覆盖现有运算符的行为。直到现在,唯一灵活重新定义运算符的方式是在 ORM 层中,使用column_property()并提供一个comparator_factory参数。因此,像 GeoAlchemy 这样的第三方库被迫以 ORM 为中心,并依赖各种技巧来应用新操作以及使其正确传播。

核心中的新运算符系统添加了一直缺失的关键点,即将新的和覆盖的运算符与类型关联起来。毕竟,真正驱动操作类型的不是列、CAST 运算符或 SQL 函数,而是表达式的类型。实现细节很少 - 只需向核心ColumnElement类型添加几个额外方法,以便它向其TypeEngine对象查询可选的一组运算符。新的或修订的操作可以与任何类型关联,可以通过对现有类型进行子类化,使用TypeDecorator,或者通过将新的Comparator对象附加到现有类型类来“全面推广”。

例如,要为Numeric类型添加对数支持:

from sqlalchemy.types import Numeric
from sqlalchemy.sql import func
class CustomNumeric(Numeric):
    class comparator_factory(Numeric.Comparator):
        def log(self, other):
            return func.log(self.expr, other)

这种新类型可以像任何其他类型一样使用:

data = Table(
    "data",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("x", CustomNumeric(10, 5)),
    Column("y", CustomNumeric(10, 5)),
)
stmt = select([data.c.x.log(data.c.y)]).where(data.c.x.log(2) < value)
print(conn.execute(stmt).fetchall())

由此带来的新功能包括立即支持 PostgreSQL 的 HSTORE 类型,以及与 PostgreSQL 的 ARRAY 类型相关的新操作。它还为现有类型开辟了更多特定于这些类型的运算符的道路,例如更多的字符串、整数和日期运算符。

另请参阅

重新定义和创建新运算符

HSTORE

#2547

插入的多值支持

Insert.values()方法现在支持字典列表,将生成多 VALUES 语句,如VALUES (), (), ...。这仅适用于支持此语法的后端,包括 PostgreSQL、SQLite 和 MySQL。这与通常的executemany()风格的 INSERT 不同:

users.insert().values(
    [
        {"name": "some name"},
        {"name": "some other name"},
        {"name": "yet another name"},
    ]
)

另请参阅

Insert.values()

#2623

类型表达式

现在可以将 SQL 表达式与类型关联起来。从历史上看,TypeEngine一直允许 Python 端函数接收绑定参数和结果行值,通过 Python 端转换函数在到达/返回数据库时进行转换。新功能允许类似的功能,但在数据库端进行:

from sqlalchemy.types import String
from sqlalchemy import func, Table, Column, MetaData
class LowerString(String):
    def bind_expression(self, bindvalue):
        return func.lower(bindvalue)
    def column_expression(self, col):
        return func.lower(col)
metadata = MetaData()
test_table = Table("test_table", metadata, Column("data", LowerString))

上面,LowerString类型定义了一个 SQL 表达式,每当test_table.c.data列在 SELECT 语句的列子句中呈现时,该表达式将被发出:

>>> print(select([test_table]).where(test_table.c.data == "HI"))
SELECT  lower(test_table.data)  AS  data
FROM  test_table
WHERE  test_table.data  =  lower(:data_1) 

这个功能也被新版 GeoAlchemy 大量使用,以根据类型规则在 SQL 中内联嵌入 PostGIS 表达式。

另请参阅

应用 SQL 级别的绑定/结果处理

#1534

核心检查系统

inspect()函数引入了新的类/对象检查系统,也适用于核心。应用于Engine会产生一个Inspector对象:

from sqlalchemy import inspect
from sqlalchemy import create_engine
engine = create_engine("postgresql://scott:tiger@localhost/test")
insp = inspect(engine)
print(insp.get_table_names())

它也可以应用于任何ClauseElement,它返回ClauseElement本身,比如TableColumnSelect等。这使得它可以在核心和 ORM 构造之间流畅地工作。

新方法Select.correlate_except()

select() 现在有一个方法Select.correlate_except(),指定“除了指定的所有 FROM 子句之外的所有 FROM 子句”。它可用于映射场景,其中相关子查询应该正常关联,除了针对特定目标可选择的情况:

class SnortEvent(Base):
    __tablename__ = "event"
    id = Column(Integer, primary_key=True)
    signature = Column(Integer, ForeignKey("signature.id"))
    signatures = relationship("Signature", lazy=False)
class Signature(Base):
    __tablename__ = "signature"
    id = Column(Integer, primary_key=True)
    sig_count = column_property(
        select([func.count("*")])
        .where(SnortEvent.signature == id)
        .correlate_except(SnortEvent)
    )

另请参阅

Select.correlate_except()

PostgreSQL HSTORE 类型

PostgreSQL 的HSTORE类型现在可以作为HSTORE使用。该类型充分利用了新的操作符系统,为 HSTORE 类型提供了一整套操作符,包括索引访问、连接和包含方法,如comparator_factory.has_key()comparator_factory.has_any()comparator_factory.matrix()

from sqlalchemy.dialects.postgresql import HSTORE
data = Table(
    "data_table",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("hstore_data", HSTORE),
)
engine.execute(select([data.c.hstore_data["some_key"]])).scalar()
engine.execute(select([data.c.hstore_data.matrix()])).scalar()

另请参阅

HSTORE

hstore

#2606

增强的 PostgreSQL ARRAY 类型

ARRAY 类型将接受一个可选的“维度”参数,将其固定到一个固定数量的维度,大大提高检索结果的效率:

# old way, still works since PG supports N-dimensions per row:
Column("my_array", postgresql.ARRAY(Integer))
# new way, will render ARRAY with correct number of [] in DDL,
# will process binds and results more efficiently as we don't need
# to guess how many levels deep to go
Column("my_array", postgresql.ARRAY(Integer, dimensions=2))

该类型还引入了新的操作符,使用新的类型特定的操作符框架。新操作包括索引访问:

result = conn.execute(select([mytable.c.arraycol[2]]))

在 SELECT 中的切片访问:

result = conn.execute(select([mytable.c.arraycol[2:4]]))

在 UPDATE 中的切片更新:

conn.execute(mytable.update().values({mytable.c.arraycol[2:3]: [7, 8]}))

独立的数组文字:

>>> from sqlalchemy.dialects import postgresql
>>> conn.scalar(select([postgresql.array([1, 2]) + postgresql.array([3, 4, 5])]))
[1, 2, 3, 4, 5]

数组连接,在下面,右侧的[4, 5, 6]被强制转换为数组文字:

select([mytable.c.arraycol + [4, 5, 6]])

另请参阅

ARRAY

array

#2441

新的可配置的 SQLite 日期、时间类型

SQLite 没有内置的 DATE、TIME 或 DATETIME 类型,而是提供了一些支持将日期和时间值存储为字符串或整数的方法。0.8 版本中增强了 SQLite 的日期和时间类型,使其更加可配置,包括“微秒”部分是可选的,以及几乎所有其他内容。

Column("sometimestamp", sqlite.DATETIME(truncate_microseconds=True))
Column(
    "sometimestamp",
    sqlite.DATETIME(
        storage_format=(
            "%(year)04d%(month)02d%(day)02d"
            "%(hour)02d%(minute)02d%(second)02d%(microsecond)06d"
        ),
        regexp="(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{6})",
    ),
)
Column(
    "somedate",
    sqlite.DATE(
        storage_format="%(month)02d/%(day)02d/%(year)04d",
        regexp="(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)",
    ),
)

非常感谢 Nate Dub 在 Pycon 2012 上的努力。

另请参阅

DATETIME

DATE

TIME

#2363

“COLLATE”在所有方言中都受支持;特别是 MySQL、PostgreSQL、SQLite

“collate”关键字,长期以来被 MySQL 方言接受,现在已经在所有 String 类型上建立,并且将在任何后端呈现,包括在使用 MetaData.create_all()cast() 等特性时:

>>> stmt = select([cast(sometable.c.somechar, String(20, collation="utf8"))])
>>> print(stmt)
SELECT  CAST(sometable.somechar  AS  VARCHAR(20)  COLLATE  "utf8")  AS  anon_1
FROM  sometable 

另见

String

#2276

“Prefixes”现在支持于 update(), delete()

面向 MySQL,一个“前缀”可以在这些结构中的任何一个中呈现。例如:

stmt = table.delete().prefix_with("LOW_PRIORITY", dialect="mysql")
stmt = table.update().prefix_with("LOW_PRIORITY", dialect="mysql")

该方法是新增的,除了已经存在于 insert(), select()Query 上的方法。

另见

Update.prefix_with()

Delete.prefix_with()

Insert.prefix_with()

Select.prefix_with()

Query.prefix_with()

#2431

完全可扩展的核心级别操作符支持

迄今为止,核心从未有过为 Column 和其他表达式构造添加新 SQL 运算符的系统,除了 ColumnOperators.op() 方法,它“刚好足够”使事情正常工作。此外,核心中也从未建立过任何系统,允许覆盖现有运算符的行为。直到现在,灵活重新定义运算符的唯一方法是在 ORM 层中,使用 column_property() 给定一个 comparator_factory 参数。因此,像 GeoAlchemy 这样的第三方库被迫是 ORM 中心的,并且依赖于一系列的黑客来应用新的操作以及使其正确传播。

核心中的新运算符系统添加了一直缺失的一个钩子,即将新的和重写的运算符与类型关联起来。毕竟,真正驱动存在哪些操作的不是列、CAST 运算符或 SQL 函数,而是表达式的类型。实现细节很少——只需向核心 ColumnElement 类型添加几个额外的方法,以便它向其 TypeEngine 对象查询一组可选的运算符。新的或修改后的操作可以与任何类型关联,可以通过对现有类型的子类化、使用 TypeDecorator 或通过将新的 Comparator 对象附加到现有类型类来进行“全面的跨越边界”的关联。

例如,要向 Numeric 类型添加对数支持:

from sqlalchemy.types import Numeric
from sqlalchemy.sql import func
class CustomNumeric(Numeric):
    class comparator_factory(Numeric.Comparator):
        def log(self, other):
            return func.log(self.expr, other)

新类型可像其他类型一样使用:

data = Table(
    "data",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("x", CustomNumeric(10, 5)),
    Column("y", CustomNumeric(10, 5)),
)
stmt = select([data.c.x.log(data.c.y)]).where(data.c.x.log(2) < value)
print(conn.execute(stmt).fetchall())

此举带来的新功能包括对 PostgreSQL 的 HSTORE 类型的支持,以及与 PostgreSQL 的 ARRAY 类型相关的新操作。它还为现有类型提供了更多专门针对这些类型的操作符的可能性,如更多字符串、整数和日期操作符。

另请参阅

重新定义和创建新运算符

HSTORE

#2547

插入的多值支持

Insert.values() 方法现在支持字典列表,这将呈现出多值语句,如 VALUES (), (), ...。这仅与支持此语法的后端相关,包括 PostgreSQL、SQLite 和 MySQL。这与通常的 executemany() 样式的 INSERT 不同:

users.insert().values(
    [
        {"name": "some name"},
        {"name": "some other name"},
        {"name": "yet another name"},
    ]
)

另请参阅

Insert.values()

#2623

类型表达式

SQL 表达式现在可以与类型关联。在历史上,TypeEngine 一直允许 Python 端函数接收绑定参数和结果行值,并在传递到/从数据库的途中通过 Python 端转换函数进行转换。新功能允许类似的功能,但在数据库端执行:

from sqlalchemy.types import String
from sqlalchemy import func, Table, Column, MetaData
class LowerString(String):
    def bind_expression(self, bindvalue):
        return func.lower(bindvalue)
    def column_expression(self, col):
        return func.lower(col)
metadata = MetaData()
test_table = Table("test_table", metadata, Column("data", LowerString))

上述中,LowerString类型定义了一个 SQL 表达式,每当test_table.c.data列在 SELECT 语句的列子句中被呈现时,该表达式就会被发出:

>>> print(select([test_table]).where(test_table.c.data == "HI"))
SELECT  lower(test_table.data)  AS  data
FROM  test_table
WHERE  test_table.data  =  lower(:data_1) 

这个特性也被新版的 GeoAlchemy 大量使用,以根据类型规则在 SQL 中内联嵌入 PostGIS 表达式。

另请参阅

应用 SQL 级绑定/结果处理

#1534

核心检查系统

引入的inspect()函数新的类/对象检查系统也适用于核心。应用到一个Engine上会产生一个Inspector对象:

from sqlalchemy import inspect
from sqlalchemy import create_engine
engine = create_engine("postgresql://scott:tiger@localhost/test")
insp = inspect(engine)
print(insp.get_table_names())

它也可以应用于任何返回自身的ClauseElement,例如TableColumnSelect等。这使它可以在核心和 ORM 构造之间流畅工作。

新方法Select.correlate_except()

select()现在有一个方法Select.correlate_except(),它指定“在除了指定的 FROM 子句之外的所有 FROM 子句上关联”。它可用于映射方案,其中相关子查询应该正常关联,除了针对特定目标可选择的情况:

class SnortEvent(Base):
    __tablename__ = "event"
    id = Column(Integer, primary_key=True)
    signature = Column(Integer, ForeignKey("signature.id"))
    signatures = relationship("Signature", lazy=False)
class Signature(Base):
    __tablename__ = "signature"
    id = Column(Integer, primary_key=True)
    sig_count = column_property(
        select([func.count("*")])
        .where(SnortEvent.signature == id)
        .correlate_except(SnortEvent)
    )

另请参阅

Select.correlate_except()

PostgreSQL HSTORE 类型

对 PostgreSQL 的HSTORE类型的支持现在可用作HSTORE。这种类型充分利用了新的运算符系统,为 HSTORE 类型提供了一整套运算符,包括索引访问、连接和包含方法,如comparator_factory.has_key()comparator_factory.has_any()comparator_factory.matrix()

from sqlalchemy.dialects.postgresql import HSTORE
data = Table(
    "data_table",
    metadata,
    Column("id", Integer, primary_key=True),
    Column("hstore_data", HSTORE),
)
engine.execute(select([data.c.hstore_data["some_key"]])).scalar()
engine.execute(select([data.c.hstore_data.matrix()])).scalar()

另请参阅

HSTORE

hstore

#2606

增强的 PostgreSQL ARRAY 类型

ARRAY 类型将接受一个可选的“维度”参数,将其固定到一个固定数量的维度,大大提高检索结果的效率:

# old way, still works since PG supports N-dimensions per row:
Column("my_array", postgresql.ARRAY(Integer))
# new way, will render ARRAY with correct number of [] in DDL,
# will process binds and results more efficiently as we don't need
# to guess how many levels deep to go
Column("my_array", postgresql.ARRAY(Integer, dimensions=2))

该类型还引入了新的操作符,使用新的类型特定的操作符框架。新操作包括索引访问:

result = conn.execute(select([mytable.c.arraycol[2]]))

在 SELECT 中的切片访问:

result = conn.execute(select([mytable.c.arraycol[2:4]]))

在 UPDATE 中的切片更新:

conn.execute(mytable.update().values({mytable.c.arraycol[2:3]: [7, 8]}))

独立的数组文字:

>>> from sqlalchemy.dialects import postgresql
>>> conn.scalar(select([postgresql.array([1, 2]) + postgresql.array([3, 4, 5])]))
[1, 2, 3, 4, 5]

数组连接,下面的右侧[4, 5, 6]被强制转换为数组文字:

select([mytable.c.arraycol + [4, 5, 6]])

另请参见

ARRAY

array

#2441

新的、可配置的 SQLite 日期、时间类型

SQLite 没有内置的 DATE,TIME 或 DATETIME  类型,而是提供了一些支持,用于将日期和时间值存储为字符串或整数。SQLite 中的日期和时间类型在 0.8  中得到了增强,可以更具体地配置特定格式,包括“微秒”部分是可选的,以及几乎所有其他内容。

Column("sometimestamp", sqlite.DATETIME(truncate_microseconds=True))
Column(
    "sometimestamp",
    sqlite.DATETIME(
        storage_format=(
            "%(year)04d%(month)02d%(day)02d"
            "%(hour)02d%(minute)02d%(second)02d%(microsecond)06d"
        ),
        regexp="(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(\d{6})",
    ),
)
Column(
    "somedate",
    sqlite.DATE(
        storage_format="%(month)02d/%(day)02d/%(year)04d",
        regexp="(?P<month>\d+)/(?P<day>\d+)/(?P<year>\d+)",
    ),
)

非常感谢 Nate Dub 在 Pycon 2012 上的努力。

另请参见

DATETIME

DATE

TIME

#2363

“COLLATE”在所有方言中都受支持;特别是 MySQL,PostgreSQL,SQLite

“collate”关键字,长期以来被 MySQL 方言接受,现在已在所有String 类型上建立,并将在任何后端上呈现,包括在使用MetaData.create_all()cast()等功能时:

>>> stmt = select([cast(sometable.c.somechar, String(20, collation="utf8"))])
>>> print(stmt)
SELECT  CAST(sometable.somechar  AS  VARCHAR(20)  COLLATE  "utf8")  AS  anon_1
FROM  sometable 

另请参见

String

#2276

现在支持“前缀”用于update(), delete()

面向 MySQL,可以在任何这些结构中呈现“前缀”。例如:

stmt = table.delete().prefix_with("LOW_PRIORITY", dialect="mysql")
stmt = table.update().prefix_with("LOW_PRIORITY", dialect="mysql")

该方法是新增的,除了已存在于insert()select()Query上的方法之外。

另请参阅

Update.prefix_with()

Delete.prefix_with()

Insert.prefix_with()

Select.prefix_with()

Query.prefix_with()

#2431


SqlAlchemy 2.0 中文文档(七十八)(5)https://developer.aliyun.com/article/1560970

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
Go 开发者
Golang设置代理
Golang设置代理GOPROXY和GOSUMDB
16681 2
Golang设置代理
|
SQL 缓存 Java
修改PostgreSQL字段长度导致cached plan must not change result type错误
修改PostgreSQL字段长度可能导致cached plan must not change result type错误
9202 0
|
3天前
|
云安全 人工智能 自然语言处理
AI说的每一句话,都靠谱吗?
阿里云提供AI全栈安全能力,其中针对AI输入与输出环节的安全合规挑战,我们构建了“开箱即用”与“按需增强”相结合的多层次、可配置的内容安全机制。
|
10天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
4天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
418 187
|
2天前
|
数据采集 消息中间件 人工智能
跨系统数据搬运的全方位解析,包括定义、痛点、技术、方法及智能体解决方案
跨系统数据搬运打通企业数据孤岛,实现CRM、ERP等系统高效互通。伴随数字化转型,全球市场规模超150亿美元,中国年增速达30%。本文详解其定义、痛点、技术原理、主流方法及智能体新范式,结合实在Agent等案例,揭示从数据割裂到智能流通的实践路径,助力企业降本增效,释放数据价值。
|
8天前
|
人工智能 自然语言处理 安全
国内主流Agent工具功能全维度对比:从技术内核到场景落地,一篇读懂所有选择
2024年全球AI Agent市场规模达52.9亿美元,预计2030年将增长至471亿美元,亚太地区增速领先。国内Agent工具呈现“百花齐放”格局,涵盖政务、金融、电商等多场景。本文深入解析实在智能实在Agent等主流产品,在技术架构、任务规划、多模态交互、工具集成等方面进行全维度对比,结合市场反馈与行业趋势,为企业及个人用户提供科学选型指南,助力高效落地AI智能体应用。