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

本文涉及的产品
云原生数据库 PolarDB MySQL 版,Serverless 5000PCU 100GB
云数据库 RDS MySQL,集群版 2核4GB 100GB
推荐场景:
搭建个人博客
云原生数据库 PolarDB PostgreSQL 版,企业版 4核16GB
推荐场景:
HTAP混合负载
简介: SqlAlchemy 2.0 中文文档(七十七)

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


新特性

事件移除 API

使用 listen()listens_for() 建立的事件现在可以使用新的 remove() 函数进行移除。传递给 remove()targetidentifierfn 参数需要与用于监听的参数完全匹配,事件将从所有已建立的位置移除:

@event.listens_for(MyClass, "before_insert", propagate=True)
def my_before_insert(mapper, connection, target):
  """listen for before_insert"""
    # ...
event.remove(MyClass, "before_insert", my_before_insert)

在上述示例中,设置了 propagate=True 标志。这意味着 my_before_insert() 被建立为 MyClass 及其所有子类的监听器。系统跟踪了 my_before_insert() 监听器函数作为此调用的结果放置的所有位置,并作为调用 remove() 的结果将其移除。

移除系统使用注册表将传递给 listen() 的参数与事件监听器的集合相关联,这些事件监听器在许多情况下是原始用户提供的函数的包装版本。该注册表大量使用弱引用,以允许所有包含的内容(例如监听器目标)在超出范围时被垃圾回收。

#2268 ### 新查询选项 API;load_only() 选项

加载器选项系统,如joinedload()subqueryload()lazyload()defer()等,都建立在一个名为Load的新系统之上。Load提供了一种“方法链式”(又名生成式)的加载器选项方法,因此,不再需要使用点号或多个属性名称将长路径连接在一起,而是为每个路径明确指定加载器样式。

虽然新方法稍微更冗长,但更容易理解,因为对哪些路径应用了哪些选项没有歧义;它简化了选项的方法签名,并为基于列的选项提供了更大的灵活性。旧系统将继续无限期保持功能,并且所有样式都可以混合使用。

旧方法

要在多元素路径中的每个链接上设置某种加载样式,必须使用_all()选项:

query(User).options(joinedload_all("orders.items.keywords"))

新方法

现在加载器选项是可链接的,因此相同的joinedload(x)方法等同地应用于每个链接,无需在joinedload()joinedload_all()之间保持清晰:

query(User).options(joinedload("orders").joinedload("items").joinedload("keywords"))

旧方法

在基于子类的路径上设置一个选项需要将路径中的所有链接拼写为类绑定属性,因为PropComparator.of_type()方法需要被调用:

session.query(Company).options(
    subqueryload_all(Company.employees.of_type(Engineer), Engineer.machines)
)

新方法

只有那些实际需要PropComparator.of_type()的路径中的元素需要被设置为类绑定属性,之后可以恢复基于字符串的名称:

session.query(Company).options(
    subqueryload(Company.employees.of_type(Engineer)).subqueryload("machines")
)

旧方法

在长路径中的最后一个链接上设置加载器选项使用的语法看起来很像应该为路径中的所有链接设置选项,导致混淆:

query(User).options(subqueryload("orders.items.keywords"))

新方法

现在可以使用defaultload()为路径中的条目拼写出路径,其中现有的加载器样式不应更改。更冗长但意图更清晰:

query(User).options(defaultload("orders").defaultload("items").subqueryload("keywords"))

仍然可以利用点号样式,特别是在跳过几个路径元素的情况下:

query(User).options(defaultload("orders.items").subqueryload("keywords"))

旧方法

在路径上使用defer()选项需要为每个列明确指定完整路径:

query(User).options(defer("orders.description"), defer("orders.isopen"))

新方式

到达目标路径的单个Load对象可以反复调用Load.defer()

query(User).options(defaultload("orders").defer("description").defer("isopen"))
Load 类

Load类可以直接用于提供“绑定”目标,特别是当存在多个父实体时:

from sqlalchemy.orm import Load
query(User, Address).options(Load(Address).joinedload("entries"))
仅加载

一个新选项load_only()实现了“除了延迟加载一切之外”的加载方式,仅加载给定的列,并延迟其余部分:

from sqlalchemy.orm import load_only
query(User).options(load_only("name", "fullname"))
# specify explicit parent entity
query(User, Address).options(Load(User).load_only("name", "fullname"))
# specify path
query(User).options(joinedload(User.addresses).load_only("email_address"))
类特定的通配符

使用Load,可以使用通配符为给定实体上的所有关系(或者列)设置加载方式,而不影响其他实体:

# lazyload all User relationships
query(User).options(Load(User).lazyload("*"))
# undefer all User columns
query(User).options(Load(User).undefer("*"))
# lazyload all Address relationships
query(User).options(defaultload(User.addresses).lazyload("*"))
# undefer all Address columns
query(User).options(defaultload(User.addresses).undefer("*"))

#1418 ### 新的text()功能

text()构造获得了新的方法:

  • TextClause.bindparams()允许灵活设置绑定参数类型和值:
# setup values
stmt = text(
    "SELECT id, name FROM user WHERE name=:name AND timestamp=:timestamp"
).bindparams(name="ed", timestamp=datetime(2012, 11, 10, 15, 12, 35))
# setup types and/or values
stmt = (
    text("SELECT id, name FROM user WHERE name=:name AND timestamp=:timestamp")
    .bindparams(bindparam("name", value="ed"), bindparam("timestamp", type_=DateTime()))
    .bindparam(timestamp=datetime(2012, 11, 10, 15, 12, 35))
)
  • TextClause.columns()取代了text()typemap选项,返回一个新的构造TextAsFrom
# turn a text() into an alias(), with a .c. collection:
stmt = text("SELECT id, name FROM user").columns(id=Integer, name=String)
stmt = stmt.alias()
stmt = select([addresses]).select_from(
    addresses.join(stmt), addresses.c.user_id == stmt.c.id
)
# or into a cte():
stmt = text("SELECT id, name FROM user").columns(id=Integer, name=String)
stmt = stmt.cte("x")
stmt = select([addresses]).select_from(
    addresses.join(stmt), addresses.c.user_id == stmt.c.id
)

#2877 ### 从 SELECT 中插入

经过几乎多年的毫无意义的拖延,这个相对较小的语法特性已经被添加,并且也被回溯到 0.8.3,所以在技术上在 0.9 中并不是“新”的。一个select()构造或其他兼容的构造可以传递给新方法Insert.from_select(),在那里它将被用于渲染一个INSERT .. SELECT构造:

>>> from sqlalchemy.sql import table, column
>>> t1 = table("t1", column("a"), column("b"))
>>> t2 = table("t2", column("x"), column("y"))
>>> print(t1.insert().from_select(["a", "b"], t2.select().where(t2.c.y == 5)))
INSERT  INTO  t1  (a,  b)  SELECT  t2.x,  t2.y
FROM  t2
WHERE  t2.y  =  :y_1 

这个结构足够智能,也可以适应 ORM 对象,比如类和Query对象:

s = Session()
q = s.query(User.id, User.name).filter_by(name="ed")
ins = insert(Address).from_select((Address.id, Address.email_address), q)

渲染:

INSERT  INTO  addresses  (id,  email_address)
SELECT  users.id  AS  users_id,  users.name  AS  users_name
FROM  users  WHERE  users.name  =  :name_1

#722 ### select()Query()上的新 FOR UPDATE 支持

尝试简化在 Core 和 ORM 中对 SELECT 语句中的 FOR UPDATE 子句的规范,并支持 PostgreSQL 和 Oracle 支持的 FOR UPDATE OF SQL。

使用核心GenerativeSelect.with_for_update(),可以单独指定FOR SHARENOWAIT等选项,而不是链接到任意字符串代码:

stmt = select([table]).with_for_update(read=True, nowait=True, of=table)

在 Posgtresql 上,上述语句可能会呈现如下:

SELECT  table.a,  table.b  FROM  table  FOR  SHARE  OF  table  NOWAIT

Query 对象获得了类似的方法 Query.with_for_update(),其行为方式相同。该方法取代了现有的 Query.with_lockmode() 方法,该方法使用不同的系统翻译 FOR UPDATE 子句。目前,“lockmode”字符串参数仍然被 Session.refresh() 方法接受。 ### 本机浮点字符串转换精度可配置的浮点类型

每当 DBAPI 返回要转换为 Python Decimal() 的 Python 浮点类型时,SQLAlchemy 所做的转换必然涉及将浮点值转换为字符串的中间步骤。此字符串转换的比例以前是硬编码为 10,现在可配置。该设置可用于 Numeric 以及 Float 类型,以及所有 SQL 和方言特定的后代类型,使用参数 decimal_return_scale。如果类型支持 .scale 参数,例如 Numeric 和一些浮点类型如 DOUBLE,则如果未另行指定,.scale 的值将用作 .decimal_return_scale 的默认值。如果 .scale.decimal_return_scale 都不存在,则默认值为 10。例如:

from sqlalchemy.dialects.mysql import DOUBLE
import decimal
data = Table(
    "data",
    metadata,
    Column("double_value", mysql.DOUBLE(decimal_return_scale=12, asdecimal=True)),
)
conn.execute(
    data.insert(),
    double_value=45.768392065789,
)
result = conn.scalar(select([data.c.double_value]))
# previously, this would typically be Decimal("45.7683920658"),
# e.g. trimmed to 10 decimal places
# now we get 12, as requested, as MySQL can support this
# much precision for DOUBLE
assert result == decimal.Decimal("45.768392065789")

#2867 ### ORM 查询的列捆绑

Bundle 允许查询一组列,然后将它们分组为查询返回的元组下的一个名称。Bundle 的最初目的是 1. 允许将“复合”ORM 列作为列式结果集中的单个值返回,而不是将它们扩展为单独的列,以及 2. 允许在 ORM 中创建自定义结果集构造,使用临时列和返回类型,而不涉及映射类的更重量级机制。

另请参阅

当按属性基础查询时,复合属性现在以其对象形式返回

使用 Bundles 分组选定属性

#2824

服务器端版本计数

ORM 的版本控制功能(现在也在配置版本计数器中记录)现在可以利用服务器端版本计数方案,例如由触发器或数据库系统列生成的方案,以及版本 _id_counter 函数本身之外的条件编程方案。通过向 version_id_generator 参数提供值 False,ORM  将使用已设置的版本标识符,或者在发出 INSERT 或 UPDATE  时同时从每行获取版本标识符。当使用服务器生成的版本标识符时,强烈建议仅在具有强大 RETURNING  支持的后端上使用此功能(PostgreSQL、SQL Server;Oracle 也支持 RETURNING,但 cx_oracle  驱动程序仅支持有限),否则额外的 SELECT 语句将增加显著的性能开销。服务器端版本计数器提供的示例说明了如何使用 PostgreSQL 的 xmin 系统列将其与 ORM 的版本控制功能集成。

另请参阅

服务器端版本计数器

#2793

include_backrefs=False 选项用于 @validates

validates() 函数现在接受一个选项 include_backrefs=True,这将跳过为从反向引用发起的事件触发验证器的情况:

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship, validates
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class A(Base):
    __tablename__ = "a"
    id = Column(Integer, primary_key=True)
    bs = relationship("B", backref="a")
    @validates("bs")
    def validate_bs(self, key, item):
        print("A.bs validator")
        return item
class B(Base):
    __tablename__ = "b"
    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey("a.id"))
    @validates("a", include_backrefs=False)
    def validate_a(self, key, item):
        print("B.a validator")
        return item
a1 = A()
a1.bs.append(B())  # prints only "A.bs validator"

#1535

PostgreSQL JSON 类型

PostgreSQL 方言现在具有一个 JSON 类型,以补充 HSTORE 类型。

另请参阅

JSON

#2581

自动映射扩展

新的扩展在0.9.1中添加,称为sqlalchemy.ext.automap。这是一个实验性扩展,它扩展了声明式的功能以及DeferredReflection类的功能。基本上,该扩展提供了一个基类AutomapBase,根据给定的表元数据自动生成映射类和它们之间的关系。

正常使用的MetaData可能是通过反射生成的,但不要求使用反射。最基本的用法说明了sqlalchemy.ext.automap如何根据反射模式提供映射类,包括关系:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine
Base = automap_base()
# engine, suppose it has two tables 'user' and 'address' set up
engine = create_engine("sqlite:///mydatabase.db")
# reflect the tables
Base.prepare(engine, reflect=True)
# mapped classes are now created with names matching that of the table
# name.
User = Base.classes.user
Address = Base.classes.address
session = Session(engine)
# rudimentary relationships are produced
session.add(Address(email_address="foo@bar.com", user=User(name="foo")))
session.commit()
# collection-based relationships are by default named "<classname>_collection"
print(u1.address_collection)

此外,AutomapBase类是一个声明性基类,并支持所有声明性的功能。可以使用“自动映射”功能与现有的明确定义的模式一起使用,仅生成关系和缺失类。命名方案和关系生成例程可以使用可调用函数来插入。

期望AutomapBase系统提供了一个快速且现代化的解决方案,解决了非常著名的SQLSoup也尝试解决的问题,即从现有数据库动态生成快速和简陋的对象模型的问题。通过严格在映射器配置级别解决该问题,并与现有的声明式类技术完全集成,AutomapBase旨在为快速自动生成临时映射的问题提供一个良好集成的方法。

另请参阅

自动映射 ### 事件移除 API

使用listen()listens_for()建立的事件现在可以使用新的remove()函数进行移除。发送给remove()targetidentifierfn参数需要与用于监听的参数完全匹配,并且事件将从建立的所有位置中移除:

@event.listens_for(MyClass, "before_insert", propagate=True)
def my_before_insert(mapper, connection, target):
  """listen for before_insert"""
    # ...
event.remove(MyClass, "before_insert", my_before_insert)

在上面的示例中,设置了propagate=True标志。这意味着my_before_insert()被建立为MyClass以及MyClass的所有子类的监听器。系统跟踪了my_before_insert()监听函数作为此调用的结果放置的所有位置,并在调用remove()后将其移除。

移除系统使用注册表将传递给listen()的参数与事件监听器集合关联,这些事件监听器在许多情况下是原始用户提供的函数的包装版本。该注册表大量使用弱引用,以允许所有包含的内容(如监听器目标)在超出范围时被垃圾回收。

#2268

新查询选项 API;load_only() 选项

加载器选项系统,如joinedload()subqueryload()lazyload()defer()等,都建立在一个名为Load的新系统之上。Load提供了一种“方法链式”(又名生成式)的加载器选项方法,因此不再需要使用点号或多个属性名称连接长路径,而是为每个路径指定明确的加载器样式。

新方法虽然稍微冗长,但更容易理解,因为对应哪些路径应用了哪些选项没有歧义;它简化了选项的方法签名,并为基于列的选项提供了更大的灵活性。旧系统将永远保持功能,并且所有样式都可以混合使用。

旧方法

要在多元素路径中的每个链接上设置特定的加载样式,必须使用_all()选项:

query(User).options(joinedload_all("orders.items.keywords"))

新方法

加载器选项现在可以链式调用,因此相同的joinedload(x)方法同样适用于每个链接,无需在joinedload()joinedload_all()之间保持清晰:

query(User).options(joinedload("orders").joinedload("items").joinedload("keywords"))

旧方法

在基于子类的路径上设置选项需要将路径中的所有链接拼写为类绑定属性,因为需要调用PropComparator.of_type()方法:

session.query(Company).options(
    subqueryload_all(Company.employees.of_type(Engineer), Engineer.machines)
)

新方法

只有实际需要PropComparator.of_type()的路径元素需要��置为类绑定属性,之后可以恢复基于字符串的名称:

session.query(Company).options(
    subqueryload(Company.employees.of_type(Engineer)).subqueryload("machines")
)

旧方法

在长路径中设置加载器选项的最后一个链接使用的语法看起来很像应该为路径中的所有链接设置选项,导致混淆:

query(User).options(subqueryload("orders.items.keywords"))

新方法

现在可以使用defaultload()来拼写路径,其中现有的加载器样式应保持不变。更冗长但意图更清晰:

query(User).options(defaultload("orders").defaultload("items").subqueryload("keywords"))

点线样式仍然可以被充分利用,特别是在跳过多个路径元素的情况下:

query(User).options(defaultload("orders.items").subqueryload("keywords"))

旧方法

需要为路径上的每个列拼写出完整路径的defer()选项:

query(User).options(defer("orders.description"), defer("orders.isopen"))

新方法

到达目标路径的单个Load对象可以反复调用Load.defer()

query(User).options(defaultload("orders").defer("description").defer("isopen"))
加载类

Load类可以直接用于提供“绑定”目标,特别是当存在多个父实体时:

from sqlalchemy.orm import Load
query(User, Address).options(Load(Address).joinedload("entries"))
仅加载

新选项load_only()实现了“除了加载之外的一切都延迟”的加载方式,仅加载给定列并推迟其余部分:

from sqlalchemy.orm import load_only
query(User).options(load_only("name", "fullname"))
# specify explicit parent entity
query(User, Address).options(Load(User).load_only("name", "fullname"))
# specify path
query(User).options(joinedload(User.addresses).load_only("email_address"))
类特定通配符

使用Load,可以使用通配符为给定实体上的所有关系(或可能列)设置加载,而不影响其他实体:

# lazyload all User relationships
query(User).options(Load(User).lazyload("*"))
# undefer all User columns
query(User).options(Load(User).undefer("*"))
# lazyload all Address relationships
query(User).options(defaultload(User.addresses).lazyload("*"))
# undefer all Address columns
query(User).options(defaultload(User.addresses).undefer("*"))

#1418

加载类

Load类可以直接用于提供“绑定”目标,特别是当存在多个父实体时:

from sqlalchemy.orm import Load
query(User, Address).options(Load(Address).joinedload("entries"))
仅加载

新选项load_only()实现了“除了加载之外的一切都延迟加载”的加载方式,仅加载给定的列并推迟其余的列:

from sqlalchemy.orm import load_only
query(User).options(load_only("name", "fullname"))
# specify explicit parent entity
query(User, Address).options(Load(User).load_only("name", "fullname"))
# specify path
query(User).options(joinedload(User.addresses).load_only("email_address"))
类特定的通配符

使用Load,可以使用通配符为给定实体上的所有关系(或可能是列)设置加载,而不影响其他实体:

# lazyload all User relationships
query(User).options(Load(User).lazyload("*"))
# undefer all User columns
query(User).options(Load(User).undefer("*"))
# lazyload all Address relationships
query(User).options(defaultload(User.addresses).lazyload("*"))
# undefer all Address columns
query(User).options(defaultload(User.addresses).undefer("*"))

#1418

新的text()功能

text()构造获得了新方法:

  • TextClause.bindparams()允许灵活设置绑定参数类型和值:
# setup values
stmt = text(
    "SELECT id, name FROM user WHERE name=:name AND timestamp=:timestamp"
).bindparams(name="ed", timestamp=datetime(2012, 11, 10, 15, 12, 35))
# setup types and/or values
stmt = (
    text("SELECT id, name FROM user WHERE name=:name AND timestamp=:timestamp")
    .bindparams(bindparam("name", value="ed"), bindparam("timestamp", type_=DateTime()))
    .bindparam(timestamp=datetime(2012, 11, 10, 15, 12, 35))
)
  • TextClause.columns()取代了text()typemap选项,返回一个新的构造TextAsFrom
# turn a text() into an alias(), with a .c. collection:
stmt = text("SELECT id, name FROM user").columns(id=Integer, name=String)
stmt = stmt.alias()
stmt = select([addresses]).select_from(
    addresses.join(stmt), addresses.c.user_id == stmt.c.id
)
# or into a cte():
stmt = text("SELECT id, name FROM user").columns(id=Integer, name=String)
stmt = stmt.cte("x")
stmt = select([addresses]).select_from(
    addresses.join(stmt), addresses.c.user_id == stmt.c.id
)

#2877

从 SELECT 插入

经过几乎多年的毫无意义的拖延,这个相对较小的语法特性已经被添加,并且也被回溯到了 0.8.3 版本,所以在技术上在 0.9 版本中并不是“新”功能。可以将select()构造或其他兼容的构造传递给新方法Insert.from_select(),其中它将被用于渲染INSERT .. SELECT构造:

>>> from sqlalchemy.sql import table, column
>>> t1 = table("t1", column("a"), column("b"))
>>> t2 = table("t2", column("x"), column("y"))
>>> print(t1.insert().from_select(["a", "b"], t2.select().where(t2.c.y == 5)))
INSERT  INTO  t1  (a,  b)  SELECT  t2.x,  t2.y
FROM  t2
WHERE  t2.y  =  :y_1 

该构造足够智能,也可以适应 ORM 对象,如类和Query对象:

s = Session()
q = s.query(User.id, User.name).filter_by(name="ed")
ins = insert(Address).from_select((Address.id, Address.email_address), q)

渲染:

INSERT  INTO  addresses  (id,  email_address)
SELECT  users.id  AS  users_id,  users.name  AS  users_name
FROM  users  WHERE  users.name  =  :name_1

#722

select()Query()上的新的 FOR UPDATE 支持

尝试简化在 Core 和 ORM 中制作SELECT语句时FOR UPDATE子句的规范,并支持 PostgreSQL 和 Oracle 支持的FOR UPDATE OF SQL。

使用核心GenerativeSelect.with_for_update(),可以单独指定选项,如FOR SHARENOWAIT,而不是链接到任意字符串代码:

stmt = select([table]).with_for_update(read=True, nowait=True, of=table)

在 Posgtresql 上述语句可能会呈现如下:

SELECT  table.a,  table.b  FROM  table  FOR  SHARE  OF  table  NOWAIT

Query 对象获得了一个类似的方法 Query.with_for_update(),其行为方式相同。该方法取代了现有的 Query.with_lockmode() 方法,该方法使用不同的系统翻译 FOR UPDATE 子句。目前,“lockmode” 字符串参数仍然被 Session.refresh() 方法接受。

本机浮点字符串转换精度可配置

每当 DBAPI 返回一个要转换为 Python Decimal() 的 Python 浮点类型时,SQLAlchemy 所做的转换必然涉及一个中间步骤,将浮点值转换为字符串。用于此字符串转换的标度以前是硬编码为 10,现在是可配置的。该设置在 Numeric 以及 Float 类型上都可用,以及所有 SQL 和特定方言的后代类型,使用参数 decimal_return_scale。如果类型支持 .scale 参数,如 Numeric 和一些浮点类型如 DOUBLE,则如果未另行指定,则 .scale 的值将用作 .decimal_return_scale 的默认值。如果 .scale.decimal_return_scale 都不存在,则默认值为 10。例如:

from sqlalchemy.dialects.mysql import DOUBLE
import decimal
data = Table(
    "data",
    metadata,
    Column("double_value", mysql.DOUBLE(decimal_return_scale=12, asdecimal=True)),
)
conn.execute(
    data.insert(),
    double_value=45.768392065789,
)
result = conn.scalar(select([data.c.double_value]))
# previously, this would typically be Decimal("45.7683920658"),
# e.g. trimmed to 10 decimal places
# now we get 12, as requested, as MySQL can support this
# much precision for DOUBLE
assert result == decimal.Decimal("45.768392065789")

#2867

ORM 查询的列捆绑

Bundle 允许查询一组列,然后将它们分组为查询返回的元组下的一个名称。Bundle 的最初目的是 1. 允许将“复合”ORM 列作为列结果集中的单个值返回,而不是将它们展开为单独的列,以及 2. 允许在 ORM 中创建自定义结果集构造,使用临时列和返回类型,而不涉及映射类的更重量级机制。

另请参见

当按属性基础查询时,复合属性现在以其对象形式返回

使用捆绑组合选定属性

#2824

服务器端版本计数

ORM 的版本控制功能(现在还在 配置版本计数器 中有文档记录)现在可以利用服务器端的版本计数方案,例如由触发器或数据库系统列生成的方案,以及版本 _id_counter 函数本身之外的条件编程方案。通过向 version_id_generator 参数提供值 False,ORM  将使用已设置的版本标识符,或者在发出 INSERT 或 UPDATE  时同时从每一行获取版本标识符。当使用服务器生成的版本标识符时,强烈建议仅在具有强大 RETURNING  支持的后端上使用此功能(PostgreSQL、SQL Server;Oracle 也支持 RETURNING,但 cx_oracle  驱动程序仅具有有限的支持),否则额外的 SELECT 语句将增加显著的性能开销。在 服务器端版本计数器 提供的示例中说明了使用  PostgreSQL xmin 系统列将其与 ORM 的版本控制功能集成的用法。

另请参阅

服务器端版本计数器

#2793

include_backrefs=False 选项用于 @validates

validates() 函数现在接受一个选项 include_backrefs=True,将为从反向引用发起事件的情况跳过触发器:

from sqlalchemy import Column, Integer, ForeignKey
from sqlalchemy.orm import relationship, validates
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class A(Base):
    __tablename__ = "a"
    id = Column(Integer, primary_key=True)
    bs = relationship("B", backref="a")
    @validates("bs")
    def validate_bs(self, key, item):
        print("A.bs validator")
        return item
class B(Base):
    __tablename__ = "b"
    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey("a.id"))
    @validates("a", include_backrefs=False)
    def validate_a(self, key, item):
        print("B.a validator")
        return item
a1 = A()
a1.bs.append(B())  # prints only "A.bs validator"

#1535

PostgreSQL JSON 类型

PostgreSQL 方言现在具有 JSON 类型,以补充 HSTORE 类型。

另请参阅

JSON

#2581

Automap 扩展

0.9.1 版本新增了一个名为sqlalchemy.ext.automap的扩展。这是一个实验性扩展,它扩展了声明式以及DeferredReflection类的功能。本质上,该扩展提供了一个基类AutomapBase,根据给定的表元数据自动生成映射类和它们之间的关系。

使用的MetaData通常可能是通过反射生成的,但不要求使用反射。最基本的用法说明了sqlalchemy.ext.automap如何能够根据反射模式提供映射类,包括关系:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine
Base = automap_base()
# engine, suppose it has two tables 'user' and 'address' set up
engine = create_engine("sqlite:///mydatabase.db")
# reflect the tables
Base.prepare(engine, reflect=True)
# mapped classes are now created with names matching that of the table
# name.
User = Base.classes.user
Address = Base.classes.address
session = Session(engine)
# rudimentary relationships are produced
session.add(Address(email_address="foo@bar.com", user=User(name="foo")))
session.commit()
# collection-based relationships are by default named "<classname>_collection"
print(u1.address_collection)

此外,AutomapBase类是一个声明基类,并支持声明的所有功能。可以将“自动映射”功能用于现有的、明确声明的模式,以仅生成关系和缺失类。可以使用可调用函数添加命名方案和关系生成例程。

希望AutomapBase系统提供了一个快速且现代化的解决方案,解决了非常著名的SQLSoup也试图解决的问题,即从现有数据库快速生成一个简单的对象模型。通过严格在映射器配置级别解决该问题,并与现有的声明类技术完全集成,AutomapBase旨在提供一个完全集成的方法来解决迅速自动生成临时映射的问题。

另请参阅

自动映射


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

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7天前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(七十一)(4)
SqlAlchemy 2.0 中文文档(七十一)
12 1
|
7天前
|
Oracle 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(七十一)(1)
SqlAlchemy 2.0 中文文档(七十一)
9 1
|
9天前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(七十九)(5)
SqlAlchemy 2.0 中文文档(七十九)
11 2
|
9天前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(七十六)(1)
SqlAlchemy 2.0 中文文档(七十六)
12 2
|
10天前
|
SQL 存储 缓存
SqlAlchemy 2.0 中文文档(八十一)(1)
SqlAlchemy 2.0 中文文档(八十一)
13 2
|
10天前
|
SQL 缓存 API
SqlAlchemy 2.0 中文文档(八十一)(3)
SqlAlchemy 2.0 中文文档(八十一)
14 1
|
10天前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(八十一)(2)
SqlAlchemy 2.0 中文文档(八十一)
18 1
|
10天前
|
存储 SQL Java
SqlAlchemy 2.0 中文文档(八十一)(4)
SqlAlchemy 2.0 中文文档(八十一)
16 1
|
10天前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(八十一)(5)
SqlAlchemy 2.0 中文文档(八十一)
16 1
|
9天前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(七十七)(2)
SqlAlchemy 2.0 中文文档(七十七)
11 0