断面 映射器配置概述 讨论了 Mapper construct,它是一种结构,用于定义如何将特定的用户定义类映射到数据库表或其他SQL构造。下面的部分描述了关于声明性系统如何构造 Mapper .
中给出的示例 具有声明性的表配置 说明针对表绑定列的映射;单个列到ORM类属性的映射在内部由 ColumnProperty 构造。还有许多其他类型的映射器属性,最常见的是 relationship() 构造。其他类型的属性包括使用 synonym() 构造,使用 column_property() 构造、延迟列和SQL表达式,这些表达式仅在访问时加载,使用 deferred() 构造。
当 imperative mapping 利用 properties 字典来建立所有映射的类属性,在声明性映射中,这些属性都与类定义内联指定,在声明性表映射的情况下,类定义内联 Column 将用于生成 Table 对象。
使用的示例映射 User 和 Address ,我们可以说明一个声明性表映射,它不仅包括 Column 对象以及关系和SQL表达式:
# mapping attributes using declarative with declarative table
# i.e. __tablename__
from sqlalchemy import Column, Integer, String, Text, ForeignKey
from sqlalchemy.orm import column_property, relationship, deferred
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
firstname = Column(String(50))
lastname = Column(String(50))
fullname = column_property(firstname + " " + lastname)
addresses = relationship("Address", back_populates="user")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
user_id = Column(ForeignKey("user.id"))
email_address = Column(String)
address_statistics = deferred(Column(Text))
user = relationship("User", back_populates="addresses")上面的声明性表映射有两个表,每个表都有一个 relationship() 引用另一个,以及由映射的简单SQL表达式 column_property() ,以及一个额外的 Column 将在“延迟”的基础上加载 deferred() 构造。有关这些特定概念的更多文档,请访问 基本关系模式 , 使用列属性 和 延迟列加载 .
属性也可以使用上面的“混合表”样式通过声明性映射来指定 Column 直接作为表的一部分的对象移动到 Table 但其他所有内容(包括组合的SQL表达式)仍将与类定义内联。需要引用 Column 直接引用 Table 对象。要使用混合表样式演示上述映射:
# mapping attributes using declarative with imperative table
# i.e. __table__
from sqlalchemy import Table
from sqlalchemy import Column, Integer, String, Text, ForeignKey
from sqlalchemy.orm import column_property, relationship, deferred
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class User(Base):
__table__ = Table(
"user",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("name", String),
Column("firstname", String(50)),
Column("lastname", String(50))
)
fullname = column_property(__table__.c.firstname + " " + __table__.c.lastname)
addresses = relationship("Address", back_populates="user")
class Address(Base):
__table__ = Table(
"address",
Base.metadata,
Column("id", Integer, primary_key=True),
Column("user_id", ForeignKey("user.id")),
Column("email_address", String),
Column("address_statistics", Text)
)
address_statistics = deferred(__table__.c.address_statistics)
user = relationship("User", back_populates="addresses")以上注意事项:
住址 Table 包含一个名为 address_statistics ,但是,我们在相同的属性名下重新映射此列,使其受 deferred() 构造。
当我们定义一个 ForeignKey 构造时,我们总是使用 表名 ,而不是映射的类名。
当我们定义 relationship() 构造,因为这些构造在两个映射类之间创建链接,其中一个必须在另一个之前定义,因此我们可以使用远程类的字符串名称来引用它。此功能还扩展到 relationship() 例如“primary join”和“order by”参数。参见章节 关系论据的后期评估 有关详细信息。
对于所有映射表单,类的映射是通过成为 Mapper 对象。最终接收这些参数的函数是 mapper() 函数中定义的前向映射函数之一传递给它 registry 对象。
对于声明形式的映射,使用 __mapper_args__ 作为声明性参数传递给字典的关键字 mapper() 功能。一些例子:
版本ID列
这个 mapper.version_id_col 和 mapper.version_id_generator 参数::
from datetime import datetime
class Widget(Base):
__tablename__ = 'widgets'
id = Column(Integer, primary_key=True)
timestamp = Column(DateTime, nullable=False)
__mapper_args__ = {
'version_id_col': timestamp,
'version_id_generator': lambda v:datetime.now()
}单表继承
这个 mapper.polymorphic_on 和 mapper.polymorphic_identity 参数::
class Person(Base):
__tablename__ = 'person'
person_id = Column(Integer, primary_key=True)
type = Column(String, nullable=False)
__mapper_args__ = dict(
polymorphic_on=type,
polymorphic_identity="person"
)
class Employee(Person):
__mapper_args__ = dict(
polymorphic_identity="employee"
)这个 __mapper_args__ 通过使用 declared_attr() 构造。部门 使用mixin组合映射层次 进一步讨论这个概念。
__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 configured0.9.3 新版功能.
metadata¶这个 MetaData 集合,通常用于将新的 Table 是不是 registry.metadata 属性关联的 registry 正在使用的对象。当使用声明性基类(如由生成的基类)时 declarative_base() 以及 registry.generate_base() ,这个 MetaData 通常也作为名为 .metadata 它直接位于基类上,因此也通过继承位于映射类上。声明性使用此属性(如果存在)来确定目标 MetaData 集合,或者如果不存在,则使用 MetaData 直接与 registry 。
也可以向此属性赋值,以便影响 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 = Column(Integer, primary_key=True)
@reg.mapped
class ClassTwo(BaseOne):
__tablename__ = 't1' # will use BaseOne.metadata
id = Column(Integer, primary_key=True)
@reg.mapped
class ClassThree(BaseTwo):
__tablename__ = 't1' # will use BaseTwo.metadata
id = Column(Integer, primary_key=True)在 1.4.3 版更改: 这个 registry.mapped() 修饰器将支持名为 .metadata 在班级上做替补 MetaData 集合,以代替 MetaData 那是在 registry 它本身。方法返回的基类的行为相匹配。 registry.generate_base() 和 sqlalchemy.orm.declarative_base() 方法/函数。注意:此功能由于1.4.0、1.4.1和1.4.2中的回归而中断,即使在使用 declarative_base() ;需要1.4.3才能恢复行为。
参见
__abstract__¶__abstract__ 使声明性完全跳过类的表或映射器的生成。类可以以与mixin相同的方式添加到层次结构中(请参见 混合和自定义基类 ,允许子类仅从特殊类扩展::
class SomeAbstractBase(Base):
__abstract__ = True
def some_helpful_method(self):
""
@declared_attr
def __mapper_args__(cls):
return {"helpful mapper arguments":True}
class MyMappedClass(SomeAbstractBase):
""一种可能的用途 __abstract__ 是使用一个 MetaData 对于不同的基础:
Base = declarative_base()
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)__table_cls__¶允许用于生成 Table 定制。这是一个非常开放的钩子,允许对 Table 那个在这里产生的:
class MyMixin(object):
@classmethod
def __table_cls__(cls, name, metadata_obj, *arg, **kw):
return Table(
"my_" + name,
metadata_obj, *arg, **kw
)上面的混音会导致 Table 为包含前缀而生成的对象 "my_" ,后跟通常使用 __tablename__ 属性。
__table_cls__ 也支持返回的情况 None 这将导致类被视为单表继承而不是其子类。这在某些自定义方案中可能很有用,可以根据表本身的参数确定应该进行单表继承,例如,如果不存在主键,则将其定义为单继承::
class AutoTable(object):
@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 = Column(Integer, primary_key=True)
class Employee(Person):
employee_name = Column(String)以上内容 Employee 类将映射为针对以下对象的单表继承 Person ; employee_name 列将添加为 Person 桌子。
flambé! the dragon and The Alchemist image designs created and generously donated by Rotem Yaari.
Created using Sphinx 4.2.0.