SqlAlchemy 2.0 中文文档(四)(4)

简介: SqlAlchemy 2.0 中文文档(四)

SqlAlchemy 2.0 中文文档(四)(3)https://developer.aliyun.com/article/1562996


声明式映射

Declarative Mapping 是在现代 SQLAlchemy 中构建映射的典型方式。最常见的模式是首先使用 DeclarativeBase 超类构造一个基类。结果基类,当被子类继承时,将对所有从它继承的子类应用声明式映射过程,相对于默认情况下新基类的本地 registry。下面的示例说明了使用声明基类然后在声明式表映射中使用它的方法:

from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
# declarative base class
class Base(DeclarativeBase):
    pass
# an example mapping using the base
class User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    fullname: Mapped[str] = mapped_column(String(30))
    nickname: Mapped[Optional[str]]

上文中,DeclarativeBase 类用于生成一个新的基类(在 SQLAlchemy 的文档中通常称为 Base,但可以使用任何想要的名称),新的映射类可以从中继承,就像上面构造了一个新的映射类 User 一样。

从 2.0 版本开始更改:DeclarativeBase 超类取代了 declarative_base() 函数和 registry.generate_base() 方法的使用;超类方法与 PEP 484 工具集成,无需使用插件。有关迁移说明,请参阅 ORM Declarative Models。

基类指的是一个维护一组相关映射类的 registry 对象,以及一个保留了一组将类映射到其中的 Table 对象的 MetaData 对象。

主要的 Declarative 映射风格在以下各节中进一步详细说明:

  • 使用声明基类 - 使用基类进行声明式映射。
  • 使用装饰器进行声明式映射(无声明基类) - 使用装饰器进行声明式映射,而不是使用基类。

在 Declarative 映射类的范围内,还有两种声明 Table 元数据的方式。它们包括:

  • mapped_column()的声明式表 - 在映射类内联声明表列,使用mapped_column()指令(或者在遗留形式中,直接使用Column对象)。mapped_column()指令也可以选择性地与类型注解结合使用,使用Mapped类可以直接提供有关映射列的一些细节。列指令与__tablename__和可选的__table_args__类级指令的组合将允许声明式映射过程构造一个要映射的Table对象。
  • 声明式与命令式表(也称为混合声明式) - 不是分别指定表名和属性,而是将明确构造的Table对象与否则以声明方式映射的类相关联。这种映射风格是“声明式”和“命令式”映射的混合体,并适用于将类映射到反射的Table对象,以及将类映射到现有 Core 构造,如连接和子查询。

声明式映射的文档继续在使用声明性映射类 ### 命令式映射

命令式经典映射是指使用registry.map_imperatively()方法配置映射类的配置,其中目标类不包含任何声明式类属性。

提示

命令式映射形式是 SQLAlchemy 在 2006 年的最初版本中少用的一种映射形式。它本质上是绕过声明式系统提供一种更“精简”的映射系统,不提供现代特性,如PEP 484支持。因此,大多数文档示例使用声明式形式,并建议新用户从声明式表配置开始。

在 2.0 版中更改:现在使用registry.map_imperatively()方法创建经典映射。sqlalchemy.orm.mapper()独立函数被有效删除。

在“经典”形式中,表元数据是分别使用Table构造创建的,然后通过registry.map_imperatively()方法与User类关联,在建立registry实例之后。通常,一个registry的单个实例共享所有彼此相关的映射类:

from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import registry
mapper_registry = registry()
user_table = Table(
    "user",
    mapper_registry.metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String(50)),
    Column("fullname", String(50)),
    Column("nickname", String(12)),
)
class User:
    pass
mapper_registry.map_imperatively(User, user_table)

关于映射属性的信息,例如与其他类的关系,通过properties字典提供。下面的示例说明了第二个Table对象,映射到名为Address的类,然后通过relationship()链接到User:

address = Table(
    "address",
    metadata_obj,
    Column("id", Integer, primary_key=True),
    Column("user_id", Integer, ForeignKey("user.id")),
    Column("email_address", String(50)),
)
mapper_registry.map_imperatively(
    User,
    user,
    properties={
        "addresses": relationship(Address, backref="user", order_by=address.c.id)
    },
)
mapper_registry.map_imperatively(Address, address)

请注意,使用命令式方法映射的类与使用声明式方法映射的类完全可互换。两个系统最终创建相同的配置,由一个Table、用户定义类和一个Mapper对象组成。当我们谈论“Mapper的行为”时,这也包括在使用声明式系统时 - 它仍然被使用,只是在幕后。 ### 声明式映射

声明式映射是在现代 SQLAlchemy 中构建映射的典型方式。最常见的模式是首先使用DeclarativeBase超类构造基类。生成的基类,在其派生的所有子类中应用声明式映射过程,相对于一个默认情况下局部于新基类的registry。下面的示例说明了使用声明基类的情况,然后在声明表映射中使用它:

from sqlalchemy import Integer, String, ForeignKey
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
# declarative base class
class Base(DeclarativeBase):
    pass
# an example mapping using the base
class User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str]
    fullname: Mapped[str] = mapped_column(String(30))
    nickname: Mapped[Optional[str]]

上面,DeclarativeBase类用于生成一个新的基类(在 SQLAlchemy 的文档中通常称为Base,但可以有任何所需的名称),从中新映射类User构造。

从版本 2.0 开始更改:DeclarativeBase超类取代了declarative_base()函数和registry.generate_base()方法的使用;超类方法集成了PEP 484工具,无需使用插件。有关迁移说明,请参阅 ORM 声明性模型。

基类指的是维护一组相关映射类的registry对象,以及维护一组映射到这些类的Table对象的MetaData对象。

主要的声明性映射样式在以下各节中进一步详细说明:

  • 使用声明性基类 - 使用基类的声明性映射。
  • 使用装饰器进行声明性映射(无声明性基类) - 使用装饰器而不是基类的声明性映射。

在声明性映射类的范围内,还有两种Table元数据声明的方式。这些包括:

  • 使用mapped_column()声明的声明性表格 - 表格列在映射类中使用mapped_column()指令内联声明(或者在传统形式中,直接使用Column对象)。mapped_column()指令还可以选择性地与使用Mapped类进行类型注释,该类可以直接提供有关映射列的一些详细信息相结合。列指令与__tablename__以及可选的__table_args__类级别指令的组合将允许声明性映射过程构造一个要映射的Table对象。
  • 声明式与命令式表格(即混合声明式) - 不是单独指定表名和属性,而是将显式构建的Table对象与在其他情况下以声明方式映射的类关联起来。这种映射方式是“声明式”和“命令式”映射的混合体,适用于诸如将类映射到反射的Table对象,以及将类映射到现有的 Core 构造,如联接和子查询的技术。

声明式映射的文档继续在用声明式映射类中。

命令式映射

命令式经典映射是指使用registry.map_imperatively()方法配置映射类的一种方法,其中目标类不包含任何声明式类属性。

提示

命令式映射形式是 SQLAlchemy 最早期发布的较少使用的映射形式。它基本上是绕过声明式系统提供更“简化”的映射系统,并且不提供现代特性,例如PEP 484支持。因此,大多数文档示例使用声明式形式,建议新用户从声明式表格配置开始。

在 2.0 版更改:registry.map_imperatively() 方法现在用于创建经典映射。sqlalchemy.orm.mapper() 独立函数已被有效移除。

在“经典”形式中,表元数据是使用Table构造单独创建的,然后通过registry.map_imperatively()方法与User类关联,在建立 registry 实例后。通常,一个registry实例共享给所有彼此相关的映射类:

from sqlalchemy import Table, Column, Integer, String, ForeignKey
from sqlalchemy.orm import registry
mapper_registry = registry()
user_table = Table(
    "user",
    mapper_registry.metadata,
    Column("id", Integer, primary_key=True),
    Column("name", String(50)),
    Column("fullname", String(50)),
    Column("nickname", String(12)),
)
class User:
    pass
mapper_registry.map_imperatively(User, user_table)

映射属性的信息,如与其他类的关系,通过properties字典提供。下面的示例说明了第二个Table对象,映射到名为Address的类,然后通过relationship()User关联:

address = Table(
    "address",
    metadata_obj,
    Column("id", Integer, primary_key=True),
    Column("user_id", Integer, ForeignKey("user.id")),
    Column("email_address", String(50)),
)
mapper_registry.map_imperatively(
    User,
    user,
    properties={
        "addresses": relationship(Address, backref="user", order_by=address.c.id)
    },
)
mapper_registry.map_imperatively(Address, address)

注意,使用命令式方法映射的类与使用声明式方法映射的类完全可互换。这两种系统最终都创建相同的配置,包括一个由Table、用户定义类和一个与之关联的Mapper对象组成的配置。当我们谈论“Mapper的行为”时,这也包括使用声明式系统 - 它仍然在幕后使用。

映射类的基本组件

通过所有映射形式,通过传递最终成为Mapper对象的构造参数,可以通过多种方式配置类的映射。传递给Mapper的参数来自给定的映射形式,包括传递给registry.map_imperatively()的参数,用于命令式映射,或者使用声明式系统时,来自与被映射的表列、SQL 表达式和关系相关联的参数以及属性的参数,如 mapper_args

Mapper类寻找的四类常规配置信息如下:

待映射的类

这是我们在应用程序中构造的类。通常情况下,这个类的结构没有限制。[1]当一个 Python 类被映射时,该类只能有一个Mapper对象。[2]

当使用声明式映射风格时,要映射的类要么是声明基类的子类,要么由装饰器或函数处理,如registry.mapped()

当使用命令式映射风格时,类直接作为map_imperatively.class_参数传递。

表格或其他来源子句对象

在绝大多数常见情况下,这是Table的实例。对于更高级的用例,它还可以指代任何一种FromClause对象,最常见的替代对象是SubqueryJoin对象。

当使用声明性映射样式进行映射时,主题表格要么是由声明性系统基于__tablename__属性和所呈现的Column对象生成的,要么是通过__table__属性建立的。这两种配置样式分别在具有映射列的声明性表格和具有命令式表格的声明性(又名混合声明性)中呈现。

当使用命令式样式进行映射时,主题表格作为map_imperatively.local_table参数按位置传递。

与映射类的“每个类一个映射器”的要求相反,作为映射主题的Table或其他FromClause对象可以与任意数量的映射关联。Mapper直接对用户定义的类进行修改,但不以任何方式修改给定的Table或其他FromClause

属性字典

这是将与映射类关联的所有属性关联起来的字典。默认情况下,Mapper 从给定的Table生成此字典的条目,形式为每个都引用映射表的单个ColumnColumnProperty对象。属性字典还将包含所有其他需要配置的MapperProperty对象,最常见的是通过relationship()构造函数生成的实例。

当使用声明式映射样式进行映射时,属性字典是由声明式系统通过扫描要映射的类以获取适当属性而生成的。请参阅使用声明式定义映射属性部分以获取有关此过程的说明。

当使用命令式映射样式进行映射时,属性字典直接作为properties参数传递给registry.map_imperatively(),该参数将其传递给Mapper.properties参数。

其他映射器配置参数

当使用声明式映射样式进行映射时,附加的映射器配置参数通过__mapper_args__类属性进行配置。使用示例请参见使用声明式定义的映射器配置选项。

当使用命令式映射样式进行映射时,关键字参数传递给registry.map_imperatively()方法,该方法将其传递给Mapper类。

接受的全部参数范围在Mapper中有文档记录。

要映射的类

这是我们应用程序中构建的一个类。通常情况下,此类的结构没有任何限制。[1] 当映射 Python 类时,该类只能有一个Mapper对象。[2]

当使用声明式映射风格进行映射时,要映射的类是声明基类的子类,或者由装饰器或函数(如registry.mapped())处理。

当使用命令式风格进行映射时,类直接作为map_imperatively.class_参数传递。

表或其他来自子句对象

在绝大多数常见情况下,这是一个Table的实例。对于更高级的用例,它也可能指的是任何类型的FromClause对象,最常见的替代对象是SubqueryJoin对象。

当使用声明式映射风格进行映射时,主题表通过声明系统基于__tablename__属性和提供的Column对象生成,或者通过__table__属性建立。这两种配置样式在使用 mapped_column() 进行声明性表配置和具有命令式表的声明式(也称为混合声明式)中介绍。

当使用命令式风格进行映射时,主题表作为map_imperatively.local_table参数按位置传递。

与映射类“每个类一个映射器”的要求相反,映射的Table或其他FromClause对象可以与任意数量的映射相关联。Mapper直接将修改应用于用户定义的类,但不以任何方式修改给定的Table或其他FromClause

属性字典

这是一个与映射类相关联的所有属性的字典。默认情况下,Mapper从给定的Table中派生此字典的条目,形成每个映射表的ColumnColumnProperty对象。属性字典还将包含要配置的所有其他种类的MapperProperty对象,最常见的是由relationship()构造生成的实例。

当使用声明性映射风格进行映射时,属性字典由声明性系统通过扫描要映射的类以找到合适的属性而生成。有关此过程的说明,请参见使用声明性定义映射属性部分。

当使用命令式映射风格进行映射时,属性字典直接作为properties参数传递给registry.map_imperatively(),它将把它传递给Mapper.properties参数。

其他映射器配置参数

当使用声明性映射风格进行映射时,额外的映射器配置参数通过__mapper_args__类属性配置。有关用法示例,请参阅使用声明性配置选项的映射器。

当使用命令式映射风格进行映射时,关键字参数传递给registry.map_imperatively()方法,该方法将它们传递给Mapper类。

接受的参数的完整范围在Mapper中有文档记录。


SqlAlchemy 2.0 中文文档(四)(5)https://developer.aliyun.com/article/1562998

相关文章
|
5月前
|
SQL 前端开发 数据库
SqlAlchemy 2.0 中文文档(六)(1)
SqlAlchemy 2.0 中文文档(六)
61 0
|
5月前
|
测试技术 API 数据库
SqlAlchemy 2.0 中文文档(九)(5)
SqlAlchemy 2.0 中文文档(九)
35 0
|
5月前
|
SQL 测试技术 API
SqlAlchemy 2.0 中文文档(一)(1)
SqlAlchemy 2.0 中文文档(一)
201 1
SqlAlchemy 2.0 中文文档(一)(1)
|
5月前
|
SQL 存储 数据库
SqlAlchemy 2.0 中文文档(一)(3)
SqlAlchemy 2.0 中文文档(一)
94 1
|
5月前
|
SQL 存储 API
SqlAlchemy 2.0 中文文档(十)(5)
SqlAlchemy 2.0 中文文档(十)
35 1
|
5月前
|
SQL API 数据库
SqlAlchemy 2.0 中文文档(四)(2)
SqlAlchemy 2.0 中文文档(四)
58 1
|
5月前
|
SQL 关系型数据库 测试技术
SqlAlchemy 2.0 中文文档(十)(1)
SqlAlchemy 2.0 中文文档(十)
38 1
|
5月前
|
SQL API 数据库
SqlAlchemy 2.0 中文文档(四)(1)
SqlAlchemy 2.0 中文文档(四)
44 1
|
5月前
|
SQL 数据库 Python
SqlAlchemy 2.0 中文文档(十)(3)
SqlAlchemy 2.0 中文文档(十)
39 1
|
5月前
|
SQL JSON 关系型数据库
SqlAlchemy 2.0 中文文档(二)(4)
SqlAlchemy 2.0 中文文档(二)
52 2