SqlAlchemy 2.0 中文文档(六)(2)

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

SqlAlchemy 2.0 中文文档(六)(1)https://developer.aliyun.com/article/1560694


带有声明性的 Mapper 配置选项

对于所有映射形式,类的映射通过成为 Mapper 对象的一部分的参数进行配置。最终接收这些参数的函数是 Mapper 函数,并且它们从定义在 registry 对象上的一个前置映射函数中传递给它。

对于映射的声明形式,映射器参数是使用 __mapper_args__ 声明性类变量指定的,该变量是一个字典,作为关键字参数传递给 Mapper 函数。一些示例:

映射特定的主键列

下面的示例说明了 Mapper.primary_key 参数的声明级别设置,它将特定列作为 ORM 应该考虑为类的主键的一部分,与架构级主键约束独立:

class GroupUsers(Base):
    __tablename__ = "group_users"
    user_id = mapped_column(String(40))
    group_id = mapped_column(String(40))
    __mapper_args__ = {"primary_key": [user_id, group_id]}

另请参阅

映射到一组显式主键列 - ORM 将显式列映射为主键列的更多背景

版本 ID 列

下面的示例说明了 Mapper.version_id_colMapper.version_id_generator 参数的声明级别设置,它们配置了一个由 ORM 维护的版本计数器,在 工作单元 刷新过程中进行更新和检查:

from datetime import datetime
class Widget(Base):
    __tablename__ = "widgets"
    id = mapped_column(Integer, primary_key=True)
    timestamp = mapped_column(DateTime, nullable=False)
    __mapper_args__ = {
        "version_id_col": timestamp,
        "version_id_generator": lambda v: datetime.now(),
    }

另请参阅

配置版本计数器 - ORM 版本计数器功能的背景

单表继承

下面的示例说明了用于配置单表继承映射时使用的 Mapper.polymorphic_onMapper.polymorphic_identity 参数的声明级别设置:

class Person(Base):
    __tablename__ = "person"
    person_id = mapped_column(Integer, primary_key=True)
    type = mapped_column(String, nullable=False)
    __mapper_args__ = dict(
        polymorphic_on=type,
        polymorphic_identity="person",
    )
class Employee(Person):
    __mapper_args__ = dict(
        polymorphic_identity="employee",
    )

另见

单表继承 - ORM 单表继承映射功能的背景介绍。

动态构建映射器参数

__mapper_args__ 字典可以通过使用 declared_attr() 构造而不是固定字典从类绑定描述符方法生成。这对于从表配置或映射类的其他方面编程派生映射器参数非常有用。动态的 __mapper_args__ 属性通常在使用声明性 Mixin 或抽象基类时非常有用。

例如,要从映射中省略具有特殊 Column.info 值的任何列,一个 Mixin 可以使用一个 __mapper_args__ 方法,该方法从 cls.__table__ 属性扫描这些列并将它们传递给 Mapper.exclude_properties 集合:

from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import declared_attr
class ExcludeColsWFlag:
    @declared_attr
    def __mapper_args__(cls):
        return {
            "exclude_properties": [
                column.key
                for column in cls.__table__.c
                if column.info.get("exclude", False)
            ]
        }
class Base(DeclarativeBase):
    pass
class SomeClass(ExcludeColsWFlag, Base):
    __tablename__ = "some_table"
    id = mapped_column(Integer, primary_key=True)
    data = mapped_column(String)
    not_needed = mapped_column(String, info={"exclude": True})

在上面的示例中,ExcludeColsWFlag Mixin 提供了一个每个类的 __mapper_args__ 钩子,它将扫描包含传递给 Column.info 参数的键/值 'exclude': TrueColumn 对象,然后将它们的字符串“键”名称添加到 Mapper.exclude_properties 集合中,这将阻止生成的 Mapper 对这些列进行任何 SQL 操作的考虑。

另见

使用 Mixin 组合映射层次结构

动态构建映射器参数

__mapper_args__ 字典可以通过使用 declared_attr() 构造而不是固定字典从类绑定描述符方法生成。这对于从表配置或映射类的其他方面编程派生映射器参数非常有用。动态的 __mapper_args__ 属性通常在使用声明性 Mixin 或抽象基类时非常有用。

例如,要从映射中省略具有特殊Column.info值的任何列,mixin 可以使用一个__mapper_args__方法从cls.__table__属性中扫描这些列,并将它们传递给Mapper.exclude_properties集合:

from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import select
from sqlalchemy import String
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import declared_attr
class ExcludeColsWFlag:
    @declared_attr
    def __mapper_args__(cls):
        return {
            "exclude_properties": [
                column.key
                for column in cls.__table__.c
                if column.info.get("exclude", False)
            ]
        }
class Base(DeclarativeBase):
    pass
class SomeClass(ExcludeColsWFlag, Base):
    __tablename__ = "some_table"
    id = mapped_column(Integer, primary_key=True)
    data = mapped_column(String)
    not_needed = mapped_column(String, info={"exclude": True})

在上面的例子中,ExcludeColsWFlag mixin 提供了一个每个类的__mapper_args__钩子,该钩子将扫描包含传递给Column.info参数的键/值'exclude': TrueColumn对象,然后将其字符串“key”名称添加到Mapper.exclude_properties集合中,这将阻止生成的Mapper考虑这些列进行任何 SQL 操作。

另请参阅

使用 Mixins 构建映射的分层结构

其他声明性映射指令

__declare_last__()

__declare_last__()钩子允许定义一个类级别函数,该函数会在MapperEvents.after_configured()事件自动调用,此事件发生在假定映射已完成且“configure”步骤已完成之后:

class MyClass(Base):
    @classmethod
    def __declare_last__(cls):
  """ """
        # do something with mappings

__declare_first__()

__declare_last__()一样,但是通过MapperEvents.before_configured()事件在映射器配置的开始时调用:

class MyClass(Base):
    @classmethod
    def __declare_first__(cls):
  """ """
        # do something before mappings are configured

metadata

MetaData 集合通常用于为新的 Table 分配,它是与正在使用的 registry 对象相关联的 registry.metadata 属性。当使用诸如 DeclarativeBase 超类生成的声明性基类,以及诸如 declarative_base()registry.generate_base() 等遗留函数时,通常也会存在这个 MetaData,它作为名为 .metadata 的属性直接存在于基类上,因此也通过继承存在于映射类上。当存在时,声明性使用此属性来确定目标 MetaData 集合,如果不存在,则使用与 registry 直接关联的 MetaData

这个属性也可以被分配到,以便对单个基类和/或 registry 的每个映射层次结构基础使用影响 MetaData 集合。这将影响到是否使用声明性基类或直接使用 registry.mapped() 装饰器,从而允许模式,例如下一节中的基于抽象基类的元数据示例,abstract。类似的模式可以使用 registry.mapped() 来说明如下:

reg = registry()
class BaseOne:
    metadata = MetaData()
class BaseTwo:
    metadata = MetaData()
@reg.mapped
class ClassOne:
    __tablename__ = "t1"  # will use reg.metadata
    id = mapped_column(Integer, primary_key=True)
@reg.mapped
class ClassTwo(BaseOne):
    __tablename__ = "t1"  # will use BaseOne.metadata
    id = mapped_column(Integer, primary_key=True)
@reg.mapped
class ClassThree(BaseTwo):
    __tablename__ = "t1"  # will use BaseTwo.metadata
    id = mapped_column(Integer, primary_key=True)

另请参阅

abstract ### __abstract__

__abstract__ 会导致声明性完全跳过为类生成表或映射器。可以像 mixin 一样在层次结构中添加类(参见 Mixin and Custom Base Classes),允许子类仅从特殊类扩展:

class SomeAbstractBase(Base):
    __abstract__ = True
    def some_helpful_method(self):
  """ """
    @declared_attr
    def __mapper_args__(cls):
        return {"helpful mapper arguments": True}
class MyMappedClass(SomeAbstractBase):
    pass

__abstract__ 的一种可能用法是为不同的基类使用不同的 MetaData

class Base(DeclarativeBase):
    pass
class DefaultBase(Base):
    __abstract__ = True
    metadata = MetaData()
class OtherBase(Base):
    __abstract__ = True
    metadata = MetaData()

在上述示例中,从 DefaultBase 继承的类将使用一个 MetaData 作为表的注册表,而从 OtherBase 继承的类将使用不同的注册表。然后,表本身可能会被创建在不同的数据库中:

DefaultBase.metadata.create_all(some_engine)
OtherBase.metadata.create_all(some_other_engine)

另请参见

使用 polymorphic_abstract 构建更深层次的继承结构 - 适用于继承层次结构的另一种“抽象”映射类形式。### __table_cls__

允许定制用于生成 Table 的可调用 / 类。这是一个非常开放的钩子,可以允许对在此生成的 Table 进行特殊定制:

class MyMixin:
    @classmethod
    def __table_cls__(cls, name, metadata_obj, *arg, **kw):
        return Table(f"my_{name}", metadata_obj, *arg, **kw)

上述的混合类将导致所有生成的 Table 对象都包含前缀 "my_",后跟通常使用 __tablename__ 属性指定的名称。

__table_cls__ 还支持返回 None 的情况,这会导致将类视为单表继承 vs. 其子类。在某些定制方案中,这可能是有用的,以确定应基于表本身的参数进行单表继承,例如,如果不存在主键,则定义为单继承:

class AutoTable:
    @declared_attr
    def __tablename__(cls):
        return cls.__name__
    @classmethod
    def __table_cls__(cls, *arg, **kw):
        for obj in arg[1:]:
            if (isinstance(obj, Column) and obj.primary_key) or isinstance(
                obj, PrimaryKeyConstraint
            ):
                return Table(*arg, **kw)
        return None
class Person(AutoTable, Base):
    id = mapped_column(Integer, primary_key=True)
class Employee(Person):
    employee_name = mapped_column(String)

上述的 Employee 类将被映射为针对 Person 的单表继承;employee_name 列将作为 Person 表的成员添加。

__declare_last__()

__declare_last__() 钩子允许定义一个类级别的函数,该函数会在 MapperEvents.after_configured() 事件之后自动调用,该事件发生在映射被认为已完成并且“配置”步骤已经结束之后:

class MyClass(Base):
    @classmethod
    def __declare_last__(cls):
  """ """
        # do something with mappings

__declare_first__()

类似于 __declare_last__(),但是在映射器配置的开始阶段通过 MapperEvents.before_configured() 事件调用:

class MyClass(Base):
    @classmethod
    def __declare_first__(cls):
  """ """
        # do something before mappings are configured

metadata

通常用于分配新TableMetaData集合是与正在使用的registry对象关联的registry.metadata属性。当使用像DeclarativeBase超类生成的声明性基类时,以及诸如declarative_base()registry.generate_base()这样的旧函数时,这个MetaData通常也作为一个名为.metadata的属性存在于直接在基类上的,并且通过继承也存在于映射类上。当存在时,声明性会使用这个属性来确定目标MetaData集合,如果不存在,则使用直接与registry关联的MetaData

此属性还可以被分配到MetaData集合上,以便对单个基类和/或registry在每个映射的层次结构上进行影响。这将在使用声明性基类或直接使用registry.mapped()装饰器时生效,从而允许像下一节中的抽象基类示例一样的模式,abstract。类似的模式可以使用registry.mapped()来说明如下:

reg = registry()
class BaseOne:
    metadata = MetaData()
class BaseTwo:
    metadata = MetaData()
@reg.mapped
class ClassOne:
    __tablename__ = "t1"  # will use reg.metadata
    id = mapped_column(Integer, primary_key=True)
@reg.mapped
class ClassTwo(BaseOne):
    __tablename__ = "t1"  # will use BaseOne.metadata
    id = mapped_column(Integer, primary_key=True)
@reg.mapped
class ClassThree(BaseTwo):
    __tablename__ = "t1"  # will use BaseTwo.metadata
    id = mapped_column(Integer, primary_key=True)

另请参阅

abstract

__abstract__

__abstract__导致声明性完全跳过为类生成表或映射。可以以与 mixin 相同的方式将类添加到层次结构中(请参阅 Mixin and Custom Base Classes),从而允许子类仅从特殊类扩展:

class SomeAbstractBase(Base):
    __abstract__ = True
    def some_helpful_method(self):
  """ """
    @declared_attr
    def __mapper_args__(cls):
        return {"helpful mapper arguments": True}
class MyMappedClass(SomeAbstractBase):
    pass

__abstract__的一个可能用法是为不同的基类使用不同的MetaData

class Base(DeclarativeBase):
    pass
class DefaultBase(Base):
    __abstract__ = True
    metadata = MetaData()
class OtherBase(Base):
    __abstract__ = True
    metadata = MetaData()

在上面,继承自 DefaultBase 的类将使用一个 MetaData 作为表的注册表,而继承自 OtherBase 的类将使用另一个注册表。然后,这些表可以在不同的数据库中创建:

DefaultBase.metadata.create_all(some_engine)
OtherBase.metadata.create_all(some_other_engine)

另请参阅

使用 polymorphic_abstract 构建更深层次的层次结构 - 一种适用于继承层次结构的“抽象”映射类的替代形式。

__table_cls__

允许定制用于生成 Table 的可调用函数/类。这是一个非常开放的钩子,可以允许对在此生成的 Table 进行特殊的定制:

class MyMixin:
    @classmethod
    def __table_cls__(cls, name, metadata_obj, *arg, **kw):
        return Table(f"my_{name}", metadata_obj, *arg, **kw)

上述混合类将导致所有生成的 Table 对象都包含前缀 "my_",后跟通常使用 __tablename__ 属性指定的名称。

__table_cls__ 也支持返回 None 的情况,这将导致将类视为单表继承与其子类。在一些定制方案中,这可能是有用的,以确定基于表本身的参数是否应该进行单表继承,例如,如果没有主键存在,则定义为单继承:

class AutoTable:
    @declared_attr
    def __tablename__(cls):
        return cls.__name__
    @classmethod
    def __table_cls__(cls, *arg, **kw):
        for obj in arg[1:]:
            if (isinstance(obj, Column) and obj.primary_key) or isinstance(
                obj, PrimaryKeyConstraint
            ):
                return Table(*arg, **kw)
        return None
class Person(AutoTable, Base):
    id = mapped_column(Integer, primary_key=True)
class Employee(Person):
    employee_name = mapped_column(String)

上述 Employee 类将被映射为单表继承,对 Person 进行映射;employee_name 列将作为 Person 表的成员添加。


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

相关文章
|
5天前
|
存储 SQL API
SqlAlchemy 2.0 中文文档(四)(5)
SqlAlchemy 2.0 中文文档(四)
13 3
|
5天前
|
SQL 存储 API
SqlAlchemy 2.0 中文文档(四)(3)
SqlAlchemy 2.0 中文文档(四)
17 3
|
5天前
|
SQL 存储 数据库
SqlAlchemy 2.0 中文文档(一)(4)
SqlAlchemy 2.0 中文文档(一)
16 1
|
5天前
|
SQL 存储 数据库
SqlAlchemy 2.0 中文文档(一)(3)
SqlAlchemy 2.0 中文文档(一)
18 1
|
5天前
|
测试技术 API 数据库
SqlAlchemy 2.0 中文文档(十)(4)
SqlAlchemy 2.0 中文文档(十)
10 1
|
5天前
|
SQL 存储 API
SqlAlchemy 2.0 中文文档(十)(5)
SqlAlchemy 2.0 中文文档(十)
10 1
|
5天前
|
SQL 数据库 Python
SqlAlchemy 2.0 中文文档(十)(3)
SqlAlchemy 2.0 中文文档(十)
11 1
|
6天前
|
SQL 缓存 关系型数据库
SqlAlchemy 2.0 中文文档(三)(2)
SqlAlchemy 2.0 中文文档(三)
13 1
|
9天前
|
SQL JSON 关系型数据库
SqlAlchemy 2.0 中文文档(二)(4)
SqlAlchemy 2.0 中文文档(二)
13 2
|
5天前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(十)(2)
SqlAlchemy 2.0 中文文档(十)
7 0