SQLAlchemy 2.0 文档
SQLAlchemy ORM
- ORM 快速入门
- ORM 映射类配置
- 关系配置
- ORM 查询指南
- 使用会话
- 事件和内部机制
- ORM 扩展
- 异步 I/O (asyncio)
- 关联代理
- 自动映射
- 预编译查询
- 声明式扩展
- ORM 映射的 Mypy / Pep-484 支持
- 变动追踪
- 排序列表
- 水平分片
- 混合属性¶
- 定义与属性行为不同的表达式行为
- 使用
inplace
创建符合 pep-484 规范的混合属性 - 定义设置器
- 允许批量 ORM 更新
- 与关系一起使用
- 构建自定义比较器
- 在子类中重用混合属性
- 混合值对象
- API 参考
hybrid_method
hybrid_property
hybrid_property.__init__()
hybrid_property.comparator()
hybrid_property.deleter()
hybrid_property.expression()
hybrid_property.extension_type
hybrid_property.getter()
hybrid_property.inplace
hybrid_property.is_attribute
hybrid_property.overrides
hybrid_property.setter()
hybrid_property.update_expression()
比较器
HybridExtensionType
- 可索引
- 备用类检测
- ORM 示例
项目版本
- 上一章: 水平分片
- 下一章: 可索引
- 上一级: 首页
- 本页内容
- 混合属性
- 定义与属性行为不同的表达式行为
- 使用
inplace
创建符合 pep-484 规范的混合属性 - 定义设置器
- 允许批量 ORM 更新
- 与关系一起使用
- 构建自定义比较器
- 在子类中重用混合属性
- 混合值对象
- API 参考
hybrid_method
hybrid_property
hybrid_property.__init__()
hybrid_property.comparator()
hybrid_property.deleter()
hybrid_property.expression()
hybrid_property.extension_type
hybrid_property.getter()
hybrid_property.inplace
hybrid_property.is_attribute
hybrid_property.overrides
hybrid_property.setter()
hybrid_property.update_expression()
比较器
HybridExtensionType
混合属性¶
在 ORM 映射类上定义具有“混合”行为的属性。
“混合”是指属性在类级别和实例级别具有不同的行为定义。
hybrid
扩展提供了一种特殊的函数装饰器形式,并且对 SQLAlchemy 的其他部分依赖性很小。它的基本工作原理可以与任何基于描述符的表达式系统一起使用。
考虑一个映射 Interval
,表示整数 start
和 end
值。我们可以在映射类上定义更高级别的函数,这些函数在类级别生成 SQL 表达式,在实例级别生成 Python 表达式评估。下面,每个用 hybrid_method
或 hybrid_property
装饰的函数可能会接收 self
作为类的实例,或者可能会直接接收类,具体取决于上下文。
from __future__ import annotations
from sqlalchemy.ext.hybrid import hybrid_method
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class Interval(Base):
__tablename__ = 'interval'
id: Mapped[int] = mapped_column(primary_key=True)
start: Mapped[int]
end: Mapped[int]
def __init__(self, start: int, end: int):
self.start = start
self.end = end
@hybrid_property
def length(self) -> int:
return self.end - self.start
@hybrid_method
def contains(self, point: int) -> bool:
return (self.start <= point) & (point <= self.end)
@hybrid_method
def intersects(self, other: Interval) -> bool:
return self.contains(other.start) | self.contains(other.end)
上面,length
属性返回 end
和 start
属性之间的差值。对于 Interval
的实例,这个减法是在 Python 中进行的,使用普通的 Python 描述符机制。
>>> i1 = Interval(5, 10)
>>> i1.length
5
在处理 Interval
类本身时,hybrid_property
描述符会使用 Interval
类作为参数来评估函数体,这在与 SQLAlchemy 表达式机制一起评估时会返回一个新的 SQL 表达式。
>>> from sqlalchemy import select
>>> print(select(Interval.length))
SELECT interval."end" - interval.start AS length
FROM interval
>>> print(select(Interval).filter(Interval.length > 10))
SELECT interval.id, interval.start, interval."end"
FROM interval
WHERE interval."end" - interval.start > :param_1
过滤方法,例如 Select.filter_by()
也支持混合属性。
>>> print(select(Interval).filter_by(length=5))
SELECT interval.id, interval.start, interval."end"
FROM interval
WHERE interval."end" - interval.start = :param_1
Interval
类示例还说明了两个方法,contains()
和 intersects()
,用 hybrid_method
装饰。这个装饰器对方法应用了与 hybrid_property
对属性应用相同的思想。这些方法返回布尔值,并利用 Python 的 |
和 &
位运算符来生成等效的实例级和 SQL 表达式级布尔行为。
>>> i1.contains(6)
True
>>> i1.contains(15)
False
>>> i1.intersects(Interval(7, 18))
True
>>> i1.intersects(Interval(25, 29))
False
>>> print(select(Interval).filter(Interval.contains(15)))
SELECT interval.id, interval.start, interval."end"
FROM interval
WHERE interval.start <= :start_1 AND interval."end" > :end_1
>>> ia = aliased(Interval)
>>> print(select(Interval, ia).filter(Interval.intersects(ia)))
SELECT interval.id, interval.start,
interval."end", interval_1.id AS interval_1_id,
interval_1.start AS interval_1_start, interval_1."end" AS interval_1_end
FROM interval, interval AS interval_1
WHERE interval.start <= interval_1.start
AND interval."end" > interval_1.start
OR interval.start <= interval_1."end"
AND interval."end" > interval_1."end"
定义与属性行为不同的表达式行为¶
在上一节中,我们使用 &
和 |
位运算符在 Interval.contains
和 Interval.intersects
方法中是很幸运的,因为我们的函数处理两个布尔值以返回一个新的布尔值。在许多情况下,在 Python 中构建函数和 SQLAlchemy SQL 表达式之间的构造有足够的差异,以至于应该定义两个单独的 Python 表达式。 hybrid
装饰器为此目的定义了一个修饰符 hybrid_property.expression()
。举个例子,我们将定义区间的半径,这需要使用绝对值函数。
from sqlalchemy import ColumnElement
from sqlalchemy import Float
from sqlalchemy import func
from sqlalchemy import type_coerce
class Interval(Base):
# ...
@hybrid_property
def radius(self) -> float:
return abs(self.length) / 2
@radius.inplace.expression
@classmethod
def _radius_expression(cls) -> ColumnElement[float]:
return type_coerce(func.abs(cls.length) / 2, Float)
在上面的例子中,首先分配给名称 Interval.radius
的 hybrid_property
通过一个后续方法 Interval._radius_expression
进行修改,使用装饰器 @radius.inplace.expression
,它将两个修饰符 hybrid_property.inplace
和 hybrid_property.expression
连接在一起。使用 hybrid_property.inplace
表示 hybrid_property.expression()
修饰符应该就地修改 Interval.radius
处的现有混合对象,而不会创建新对象。有关此修饰符及其原理的说明将在下一节 使用 inplace 创建符合 pep-484 规范的混合属性 中讨论。使用 @classmethod
是可选的,严格来说是为了向类型工具提示在这个例子中 cls
预计是 Interval
类,而不是 Interval
的实例。
注意
hybrid_property.inplace
以及用于正确类型支持的 @classmethod
从 SQLAlchemy 2.0.4 开始可用,在早期版本中不起作用。
现在 Interval.radius
包含一个表达式元素,当在类级别访问 Interval.radius
时会返回 SQL 函数 ABS()
。
>>> from sqlalchemy import select
>>> print(select(Interval).filter(Interval.radius > 5))
SELECT interval.id, interval.start, interval."end"
FROM interval
WHERE abs(interval."end" - interval.start) / :abs_1 > :param_1
使用 inplace
创建符合 pep-484 规范的混合属性¶
在上一节中,我们演示了一个hybrid_property
装饰器,它包含两个独立的被装饰的函数,最终生成一个被引用为 Interval.radius
的对象属性。 实际上,我们可以为hybrid_property
使用几种不同的修饰符,包括hybrid_property.expression()
、hybrid_property.setter()
和hybrid_property.update_expression()
。
SQLAlchemy 的hybrid_property
装饰器旨在以与 Python 的内置 @property
装饰器相同的方式添加这些方法,其中习惯用法是继续重复定义属性,每次使用**相同的属性名**,如下例所示,它说明了如何使用 hybrid_property.setter()
和 hybrid_property.expression()
为 Interval.radius
描述符。
# correct use, however is not accepted by pep-484 tooling
class Interval(Base):
# ...
@hybrid_property
def radius(self):
return abs(self.length) / 2
@radius.setter
def radius(self, value):
self.length = value * 2
@radius.expression
def radius(cls):
return type_coerce(func.abs(cls.length) / 2, Float)
上面有三个 Interval.radius
方法,但是由于每个方法都被装饰,首先是被hybrid_property
装饰器装饰,然后是被 @radius
本身装饰,最终效果是 Interval.radius
是一个具有三个不同函数的单个属性。 这种使用方法来自Python 文档中对 @property 的使用。 重要的是要注意,@property
和hybrid_property
的工作方式,**每次都会创建一个描述符的副本**。 也就是说,每次调用 @radius.expression
、@radius.setter
等等都会创建一个全新的对象。 这允许在子类中重新定义属性而不会出现问题(请参阅本节后面的跨子类重用混合属性,了解如何使用它)。
但是,上述方法与 mypy 和 pyright 等类型工具不兼容。 Python 自己的 @property
装饰器没有这个限制,仅仅是因为这些工具对 @property 的行为进行了硬编码,这意味着在PEP 484 兼容性下,SQLAlchemy 无法使用这种语法。
为了在保持类型合规性的同时生成合理的语法,hybrid_property.inplace
装饰器允许对同一装饰器使用不同的方法名称,同时仍然在同一个名称下生成单个装饰器。
# correct use which is also accepted by pep-484 tooling
class Interval(Base):
# ...
@hybrid_property
def radius(self) -> float:
return abs(self.length) / 2
@radius.inplace.setter
def _radius_setter(self, value: float) -> None:
# for example only
self.length = value * 2
@radius.inplace.expression
@classmethod
def _radius_expression(cls) -> ColumnElement[float]:
return type_coerce(func.abs(cls.length) / 2, Float)
使用 hybrid_property.inplace
进一步限定了装饰器的使用,即不应该创建新的副本,从而保留 Interval.radius
名称,同时允许额外的 Interval._radius_setter
和 Interval._radius_expression
方法使用不同的名称。
版本 2.0.4 中的新功能: 添加了 hybrid_property.inplace
,允许以更简洁的方式构建复合 hybrid_property
对象,而无需使用重复的方法名称。 此外,允许在 hybrid_property.expression
、hybrid_property.update_expression
和 hybrid_property.comparator
中使用 @classmethod
,以允许类型工具将 cls
识别为类而不是方法签名中的实例。
定义 Setter¶
hybrid_property.setter()
修饰符允许构建自定义 setter 方法,该方法可以修改对象上的值。
class Interval(Base):
# ...
@hybrid_property
def length(self) -> int:
return self.end - self.start
@length.inplace.setter
def _length_setter(self, value: int) -> None:
self.end = self.start + value
现在,在设置时会调用 length(self, value)
方法。
>>> i1 = Interval(5, 10)
>>> i1.length
5
>>> i1.length = 12
>>> i1.end
17
允许批量 ORM 更新¶
混合属性可以定义一个自定义的“UPDATE”处理程序,用于在使用 ORM 启用的更新时,允许混合属性在更新的 SET 子句中使用。
通常,在使用混合属性与update()
一起时,SQL 表达式用作 SET 目标的列。 如果我们的 Interval
类有一个与 Interval.start
关联的混合属性 start_point
,那么可以将其直接替换。
from sqlalchemy import update
stmt = update(Interval).values({Interval.start_point: 10})
但是,在使用像 Interval.length
这样的复合混合属性时,此混合属性表示不止一列。 我们可以设置一个处理程序来处理传递到 VALUES 表达式中的值,该值可以影响这一点,使用 hybrid_property.update_expression()
装饰器。 一个与我们的 setter 类似的处理程序将是
from typing import List, Tuple, Any
class Interval(Base):
# ...
@hybrid_property
def length(self) -> int:
return self.end - self.start
@length.inplace.setter
def _length_setter(self, value: int) -> None:
self.end = self.start + value
@length.inplace.update_expression
def _length_update_expression(cls, value: Any) -> List[Tuple[Any, Any]]:
return [
(cls.end, cls.start + value)
]
上面,如果我们在 UPDATE 表达式中使用 Interval.length
,我们将得到一个混合 SET 表达式。
>>> from sqlalchemy import update
>>> print(update(Interval).values({Interval.length: 25}))
UPDATE interval SET "end"=(interval.start + :start_1)
ORM 会自动处理此 SET 表达式。
另请参阅
ORM 启用的 INSERT、UPDATE 和 DELETE 语句 - 包括有关 ORM 启用的 UPDATE 语句的背景信息。
与关系一起使用¶
创建与相关对象一起使用的混合属性,与创建基于列的数据的混合属性相比,并没有本质上的区别。 对不同表达式的需求往往更大。 我们将演示的两个变体是“依赖连接”混合属性和“相关子查询”混合属性。
依赖连接的关系混合属性¶
考虑以下声明式映射,它将 User
与 SavingsAccount
关联起来。
from __future__ import annotations
from decimal import Decimal
from typing import cast
from typing import List
from typing import Optional
from sqlalchemy import ForeignKey
from sqlalchemy import Numeric
from sqlalchemy import String
from sqlalchemy import SQLColumnExpression
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
class Base(DeclarativeBase):
pass
class SavingsAccount(Base):
__tablename__ = 'account'
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey('user.id'))
balance: Mapped[Decimal] = mapped_column(Numeric(15, 5))
owner: Mapped[User] = relationship(back_populates="accounts")
class User(Base):
__tablename__ = 'user'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100))
accounts: Mapped[List[SavingsAccount]] = relationship(
back_populates="owner", lazy="selectin"
)
@hybrid_property
def balance(self) -> Optional[Decimal]:
if self.accounts:
return self.accounts[0].balance
else:
return None
@balance.inplace.setter
def _balance_setter(self, value: Optional[Decimal]) -> None:
assert value is not None
if not self.accounts:
account = SavingsAccount(owner=self)
else:
account = self.accounts[0]
account.balance = value
@balance.inplace.expression
@classmethod
def _balance_expression(cls) -> SQLColumnExpression[Optional[Decimal]]:
return cast("SQLColumnExpression[Optional[Decimal]]", SavingsAccount.balance)
上面的混合属性 balance
与该用户帐户列表中的第一个 SavingsAccount
条目一起使用。 Python 中的 getter/setter 方法可以将 accounts
视为 Python 列表,该列表在 self
上可用。
提示
上面的示例中,User.balance
的 getter 访问 self.acccounts
集合,该集合通常会通过在 User.balance
的selectinload()
加载器策略上配置的relationship()
加载。 当在 relationship()
上没有明确指定时,默认的加载器策略是lazyload()
,它会按需发出 SQL。 在使用 asyncio 时,不支持按需加载器,例如lazyload()
,因此应注意确保在使用 asyncio 时,self.accounts
集合可供此混合属性访问器访问。
在表达式级别,预计 User
类将用于适当的上下文中,以便存在对 SavingsAccount
的适当连接。
>>> from sqlalchemy import select
>>> print(select(User, User.balance).
... join(User.accounts).filter(User.balance > 5000))
SELECT "user".id AS user_id, "user".name AS user_name,
account.balance AS account_balance
FROM "user" JOIN account ON "user".id = account.user_id
WHERE account.balance > :balance_1
但是,需要注意的是,虽然实例级访问器需要担心 self.accounts
是否存在,但在 SQL 表达式级别,这个问题表现形式有所不同,我们基本上会使用外连接。
>>> from sqlalchemy import select
>>> from sqlalchemy import or_
>>> print (select(User, User.balance).outerjoin(User.accounts).
... filter(or_(User.balance < 5000, User.balance == None)))
SELECT "user".id AS user_id, "user".name AS user_name,
account.balance AS account_balance
FROM "user" LEFT OUTER JOIN account ON "user".id = account.user_id
WHERE account.balance < :balance_1 OR account.balance IS NULL
相关子查询关系混合¶
当然,我们可以放弃对包含查询中使用的连接的依赖,而选择相关子查询,它可以移植地打包到一个单列表达式中。相关子查询更具可移植性,但通常在 SQL 级别上的性能更差。使用与 使用 column_property 中说明的技术相同,我们可以调整我们的 SavingsAccount
示例以聚合所有帐户的余额,并使用相关子查询作为列表达式。
from __future__ import annotations
from decimal import Decimal
from typing import List
from sqlalchemy import ForeignKey
from sqlalchemy import func
from sqlalchemy import Numeric
from sqlalchemy import select
from sqlalchemy import SQLColumnExpression
from sqlalchemy import String
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
class Base(DeclarativeBase):
pass
class SavingsAccount(Base):
__tablename__ = 'account'
id: Mapped[int] = mapped_column(primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey('user.id'))
balance: Mapped[Decimal] = mapped_column(Numeric(15, 5))
owner: Mapped[User] = relationship(back_populates="accounts")
class User(Base):
__tablename__ = 'user'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100))
accounts: Mapped[List[SavingsAccount]] = relationship(
back_populates="owner", lazy="selectin"
)
@hybrid_property
def balance(self) -> Decimal:
return sum((acc.balance for acc in self.accounts), start=Decimal("0"))
@balance.inplace.expression
@classmethod
def _balance_expression(cls) -> SQLColumnExpression[Decimal]:
return (
select(func.sum(SavingsAccount.balance))
.where(SavingsAccount.user_id == cls.id)
.label("total_balance")
)
上面的配方将为我们提供 balance
列,它渲染了一个相关的 SELECT。
>>> from sqlalchemy import select
>>> print(select(User).filter(User.balance > 400))
SELECT "user".id, "user".name
FROM "user"
WHERE (
SELECT sum(account.balance) AS sum_1 FROM account
WHERE account.user_id = "user".id
) > :param_1
构建自定义比较器¶
混合属性还包含一个助手,允许构建自定义比较器。比较器对象允许对每个 SQLAlchemy 表达式运算符的行为进行单独定制。它们在创建具有 SQL 方面高度特异性行为的自定义类型时很有用。
注意
在本节中介绍的 hybrid_property.comparator()
装饰器 **取代** 了使用 hybrid_property.expression()
装饰器。它们不能一起使用。
以下示例类允许对名为 word_insensitive
的属性进行不区分大小写的比较。
from __future__ import annotations
from typing import Any
from sqlalchemy import ColumnElement
from sqlalchemy import func
from sqlalchemy.ext.hybrid import Comparator
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
class Base(DeclarativeBase):
pass
class CaseInsensitiveComparator(Comparator[str]):
def __eq__(self, other: Any) -> ColumnElement[bool]: # type: ignore[override] # noqa: E501
return func.lower(self.__clause_element__()) == func.lower(other)
class SearchWord(Base):
__tablename__ = 'searchword'
id: Mapped[int] = mapped_column(primary_key=True)
word: Mapped[str]
@hybrid_property
def word_insensitive(self) -> str:
return self.word.lower()
@word_insensitive.inplace.comparator
@classmethod
def _word_insensitive_comparator(cls) -> CaseInsensitiveComparator:
return CaseInsensitiveComparator(cls.word)
在上面,针对 word_insensitive
的 SQL 表达式将对两边都应用 LOWER()
SQL 函数。
>>> from sqlalchemy import select
>>> print(select(SearchWord).filter_by(word_insensitive="Trucks"))
SELECT searchword.id, searchword.word
FROM searchword
WHERE lower(searchword.word) = lower(:lower_1)
上面的 CaseInsensitiveComparator
实施了 ColumnOperators
接口的一部分。可以使用 Operators.operate()
将像小写转换这样的“强制转换”操作应用于所有比较操作(即 eq
、lt
、gt
等)。
class CaseInsensitiveComparator(Comparator):
def operate(self, op, other, **kwargs):
return op(
func.lower(self.__clause_element__()),
func.lower(other),
**kwargs,
)
在子类之间重复使用混合属性¶
可以从超类引用混合,以允许修改方法,例如 hybrid_property.getter()
、hybrid_property.setter()
,以便在子类上重新定义这些方法。这类似于标准 Python @property
对象的工作方式。
class FirstNameOnly(Base):
# ...
first_name: Mapped[str]
@hybrid_property
def name(self) -> str:
return self.first_name
@name.inplace.setter
def _name_setter(self, value: str) -> None:
self.first_name = value
class FirstNameLastName(FirstNameOnly):
# ...
last_name: Mapped[str]
# 'inplace' is not used here; calling getter creates a copy
# of FirstNameOnly.name that is local to FirstNameLastName
@FirstNameOnly.name.getter
def name(self) -> str:
return self.first_name + ' ' + self.last_name
@name.inplace.setter
def _name_setter(self, value: str) -> None:
self.first_name, self.last_name = value.split(' ', 1)
在上面,FirstNameLastName
类引用来自 FirstNameOnly.name
的混合,以便重新利用其 getter 和 setter 用于子类。
当重写 hybrid_property.expression()
和 hybrid_property.comparator()
作为对超类的第一个引用时,这些名称与类级别上同名访问器冲突,该访问器是 QueryableAttribute
对象在类级别返回的。要直接引用父类描述符时重写这些方法,请添加特殊限定符 hybrid_property.overrides
,它将对受控属性进行反引用,使其回到混合对象。
class FirstNameLastName(FirstNameOnly):
# ...
last_name: Mapped[str]
@FirstNameOnly.name.overrides.expression
@classmethod
def name(cls):
return func.concat(cls.first_name, ' ', cls.last_name)
混合值对象¶
请注意,在我们之前的示例中,如果我们要将 SearchWord
实例的 word_insensitive
属性与一个普通的 Python 字符串进行比较,那么普通的 Python 字符串将不会被强制转换为小写 - 我们构建的 CaseInsensitiveComparator
,由 @word_insensitive.comparator
返回,只适用于 SQL 方面。
自定义比较器的更全面的形式是构建一个混合值对象。此技术将目标值或表达式应用于一个值对象,然后由访问器在所有情况下返回该值对象。值对象允许控制对值的 所有操作,以及如何处理比较值,包括 SQL 表达式方面和 Python 值方面。用新的 CaseInsensitiveWord
类替换之前的 CaseInsensitiveComparator
类。
class CaseInsensitiveWord(Comparator):
"Hybrid value representing a lower case representation of a word."
def __init__(self, word):
if isinstance(word, basestring):
self.word = word.lower()
elif isinstance(word, CaseInsensitiveWord):
self.word = word.word
else:
self.word = func.lower(word)
def operate(self, op, other, **kwargs):
if not isinstance(other, CaseInsensitiveWord):
other = CaseInsensitiveWord(other)
return op(self.word, other.word, **kwargs)
def __clause_element__(self):
return self.word
def __str__(self):
return self.word
key = 'word'
"Label to apply to Query tuple results"
在上面,CaseInsensitiveWord
对象表示 self.word
,它可能是一个 SQL 函数,也可能是一个 Python 本机。通过重写 operate()
和 __clause_element__()
以使用 self.word
进行工作,所有比较操作都将针对 word
的“转换”形式工作,无论它是在 SQL 方面还是 Python 方面。我们的 SearchWord
类现在可以无条件地从单个混合调用中提供 CaseInsensitiveWord
对象。
class SearchWord(Base):
__tablename__ = 'searchword'
id: Mapped[int] = mapped_column(primary_key=True)
word: Mapped[str]
@hybrid_property
def word_insensitive(self) -> CaseInsensitiveWord:
return CaseInsensitiveWord(self.word)
现在,word_insensitive
属性具有普遍的不区分大小写的比较行为,包括 SQL 表达式与 Python 表达式(请注意,Python 值在此处在 Python 方面被转换为小写)。
>>> print(select(SearchWord).filter_by(word_insensitive="Trucks"))
SELECT searchword.id AS searchword_id, searchword.word AS searchword_word
FROM searchword
WHERE lower(searchword.word) = :lower_1
SQL 表达式与 SQL 表达式
>>> from sqlalchemy.orm import aliased
>>> sw1 = aliased(SearchWord)
>>> sw2 = aliased(SearchWord)
>>> print(
... select(sw1.word_insensitive, sw2.word_insensitive).filter(
... sw1.word_insensitive > sw2.word_insensitive
... )
... )
SELECT lower(searchword_1.word) AS lower_1,
lower(searchword_2.word) AS lower_2
FROM searchword AS searchword_1, searchword AS searchword_2
WHERE lower(searchword_1.word) > lower(searchword_2.word)
仅 Python 表达式
>>> ws1 = SearchWord(word="SomeWord")
>>> ws1.word_insensitive == "sOmEwOrD"
True
>>> ws1.word_insensitive == "XOmEwOrX"
False
>>> print(ws1.word_insensitive)
someword
混合值模式对于可能有多种表示形式的任何类型的值非常有用,例如时间戳、时间增量、度量单位、货币和加密密码。
API 参考¶
对象名称 | 描述 |
---|---|
一个辅助类,允许轻松构建自定义 |
|
一个装饰器,允许定义具有实例级和类级行为的 Python 对象方法。 |
|
一个装饰器,允许定义具有实例级和类级行为的 Python 描述符。 |
|
一个枚举。 |
- class sqlalchemy.ext.hybrid.hybrid_method¶
一个装饰器,允许定义具有实例级和类级行为的 Python 对象方法。
类签名
class
sqlalchemy.ext.hybrid.hybrid_method
(sqlalchemy.orm.base.InspectionAttrInfo
、typing.Generic
)-
方法
sqlalchemy.ext.hybrid.hybrid_method.
__init__(func: Callable[[Concatenate[Any, _P]], _R], expr: Callable[[Concatenate[Any, _P]], SQLCoreOperations[_R]] | None = None)¶ 创建一个新的
hybrid_method
。通常使用装饰器。
from sqlalchemy.ext.hybrid import hybrid_method class SomeClass: @hybrid_method def value(self, x, y): return self._value + x + y @value.expression @classmethod def value(cls, x, y): return func.some_function(cls._value, x, y)
-
方法
sqlalchemy.ext.hybrid.hybrid_method.
expression(expr: Callable[[Concatenate[Any, _P]], SQLCoreOperations[_R]]) → hybrid_method[_P, _R]¶ 提供一个修饰器,用于定义生成 SQL 表达式的函数。
-
属性
sqlalchemy.ext.hybrid.hybrid_method.
extension_type: InspectionAttrExtensionType = 'HYBRID_METHOD'¶ 扩展类型,如果没有则为
NotExtension.NOT_EXTENSION
-
属性
sqlalchemy.ext.hybrid.hybrid_method.
inplace¶ 返回此
hybrid_method
的就地修改器。当调用
hybrid_method.expression()
装饰器时,hybrid_method
类已经执行了“就地”修改,因此此属性返回 Self。2.0.4 版新增。
-
属性
sqlalchemy.ext.hybrid.hybrid_method.
is_attribute = True¶ 如果此对象是 Python 描述符,则为 True。
这可以指代多种类型。通常是一个
QueryableAttribute
,它代表MapperProperty
处理属性事件。但也可以是扩展类型,例如AssociationProxy
或hybrid_property
。InspectionAttr.extension_type
将引用一个常量,该常量标识特定子类型。
-
方法
- 类 sqlalchemy.ext.hybrid.hybrid_property¶
一个装饰器,允许定义具有实例级和类级行为的 Python 描述符。
成员
__init__(), comparator(), deleter(), expression(), extension_type, getter(), inplace, is_attribute, overrides, setter(), update_expression()
类签名
class
sqlalchemy.ext.hybrid.hybrid_property
(sqlalchemy.orm.base.InspectionAttrInfo
,sqlalchemy.orm.base.ORMDescriptor
)-
方法
sqlalchemy.ext.hybrid.hybrid_property.
__init__(fget: _HybridGetterType[_T], fset: _HybridSetterType[_T] | None = None, fdel: _HybridDeleterType[_T] | None = None, expr: _HybridExprCallableType[_T] | None = None, custom_comparator: Comparator[_T] | None = None, update_expr: _HybridUpdaterType[_T] | None = None)¶ 创建一个新的
hybrid_property
。通常使用装饰器。
from sqlalchemy.ext.hybrid import hybrid_property class SomeClass: @hybrid_property def value(self): return self._value @value.setter def value(self, value): self._value = value
-
方法
sqlalchemy.ext.hybrid.hybrid_property.
comparator(comparator: _HybridComparatorCallableType[_T]) → hybrid_property[_T]¶ 提供一个修饰器,用于定义自定义的比较器生成方法。
装饰方法的返回值应为
Comparator
的实例。注意
hybrid_property.comparator()
修饰器 **替换** 了hybrid_property.expression()
修饰器的使用。它们不能一起使用。当在类级别调用混合属性时,此处提供的
Comparator
对象会被包装在一个专门的QueryableAttribute
中,该对象与 ORM 用于表示其他映射属性的对象类型相同。这样做的原因是为了让其他类级别属性(如文档字符串和对混合属性本身的引用)能够在返回的结构中保留,而无需对传入的原始比较器对象进行任何修改。注意
当从拥有类引用混合属性(例如
SomeClass.some_hybrid
)时,会返回QueryableAttribute
的实例,表示该混合属性的表达式或比较器对象。但是,该对象本身具有名为expression
和comparator
的访问器;因此,当尝试在子类上覆盖这些修饰器时,可能需要首先使用hybrid_property.overrides
修饰符对其进行限定。有关详细信息,请参阅该修饰符。
-
方法
sqlalchemy.ext.hybrid.hybrid_property.
deleter(fdel: _HybridDeleterType[_T]) → hybrid_property[_T]¶ 提供一个修饰器,用于定义删除方法。
-
方法
sqlalchemy.ext.hybrid.hybrid_property.
expression(expr: _HybridExprCallableType[_T]) → hybrid_property[_T]¶ 提供一个修饰器,用于定义生成 SQL 表达式的函数。
当在类级别调用混合属性时,此处提供的 SQL 表达式会被包装在一个专门的
QueryableAttribute
中,该对象与 ORM 用于表示其他映射属性的对象类型相同。这样做的原因是为了让其他类级别属性(如文档字符串和对混合属性本身的引用)能够在返回的结构中保留,而无需对传入的原始 SQL 表达式进行任何修改。注意
当从拥有类引用混合属性(例如
SomeClass.some_hybrid
)时,会返回QueryableAttribute
的实例,表示该混合属性的表达式或比较器对象,以及该混合属性本身。但是,该对象本身具有名为expression
和comparator
的访问器;因此,当尝试在子类上覆盖这些修饰器时,可能需要首先使用hybrid_property.overrides
修饰符对其进行限定。有关详细信息,请参阅该修饰符。另请参阅
-
属性
sqlalchemy.ext.hybrid.hybrid_property.
extension_type: InspectionAttrExtensionType = 'HYBRID_PROPERTY'¶ 扩展类型,如果没有则为
NotExtension.NOT_EXTENSION
-
方法
sqlalchemy.ext.hybrid.hybrid_property.
getter(fget: _HybridGetterType[_T]) → hybrid_property[_T]¶ 提供一个修饰器,用于定义 getter 方法。
新版 1.2 中新增。
-
属性
sqlalchemy.ext.hybrid.hybrid_property.
inplace¶ 返回此
hybrid_property
的就地变异器。这样允许对混合属性进行就地变异,允许重用具有特定名称的第一个混合属性方法,以便添加更多方法而不必给这些方法命名相同,例如:
class Interval(Base): # ... @hybrid_property def radius(self) -> float: return abs(self.length) / 2 @radius.inplace.setter def _radius_setter(self, value: float) -> None: self.length = value * 2 @radius.inplace.expression def _radius_expression(cls) -> ColumnElement[float]: return type_coerce(func.abs(cls.length) / 2, Float)
2.0.4 版新增。
-
属性
sqlalchemy.ext.hybrid.hybrid_property.
is_attribute = True¶ 如果此对象是 Python 描述符,则为 True。
这可以指代多种类型。通常是一个
QueryableAttribute
,它代表MapperProperty
处理属性事件。但也可以是扩展类型,例如AssociationProxy
或hybrid_property
。InspectionAttr.extension_type
将引用一个常量,该常量标识特定子类型。
-
属性
sqlalchemy.ext.hybrid.hybrid_property.
overrides¶ 用于覆盖现有属性的方法的前缀。
hybrid_property.overrides
访问器仅返回该混合属性对象,当从父类在类级别调用它时,将取消引用在此级别返回的“仪表化属性”,并允许修改修饰器,例如hybrid_property.expression()
和hybrid_property.comparator()
,以便使用它们而不与通常存在于QueryableAttribute
上的同名属性冲突。class SuperClass: # ... @hybrid_property def foobar(self): return self._foobar class SubClass(SuperClass): # ... @SuperClass.foobar.overrides.expression def foobar(cls): return func.subfoobar(self._foobar)
新版 1.2 中新增。
另请参阅
-
方法
sqlalchemy.ext.hybrid.hybrid_property.
setter(fset: _HybridSetterType[_T]) → hybrid_property[_T]¶ 提供一个修饰器,用于定义 setter 方法。
-
方法
sqlalchemy.ext.hybrid.hybrid_property.
update_expression(meth: _HybridUpdaterType[_T]) → hybrid_property[_T]¶ 提供一个修饰器,用于定义生成 UPDATE 元组的方法。
该方法接受一个值,该值将被渲染到 UPDATE 语句的 SET 子句中。该方法应该将该值处理成适合最终 SET 子句的单个列表达式,并将它们作为 2 元组的序列返回。每个元组包含一个列表达式作为键,以及要渲染的值。
例如:
class Person(Base): # ... first_name = Column(String) last_name = Column(String) @hybrid_property def fullname(self): return first_name + " " + last_name @fullname.update_expression def fullname(cls, value): fname, lname = value.split(" ", 1) return [ (cls.first_name, fname), (cls.last_name, lname) ]
新版 1.2 中新增。
-
方法
- 类 sqlalchemy.ext.hybrid.Comparator¶
一个辅助类,允许轻松构建自定义
PropComparator
类,用于与混合一起使用。
- 类 sqlalchemy.ext.hybrid.HybridExtensionType¶
一个枚举。
-
属性
sqlalchemy.ext.hybrid.HybridExtensionType.
HYBRID_METHOD = 'HYBRID_METHOD'¶ 表示类型为
hybrid_method
的InspectionAttr
的符号。分配给
InspectionAttr.extension_type
属性。另请参阅
Mapper.all_orm_attributes
-
属性
sqlalchemy.ext.hybrid.HybridExtensionType.
HYBRID_PROPERTY = 'HYBRID_PROPERTY'¶ - 表示类型为
hybrid_method
的InspectionAttr
的 符号。
分配给
InspectionAttr.extension_type
属性。另请参阅
Mapper.all_orm_attributes
- 表示类型为
-
属性
flambé! 龙和 炼金术士 图像设计由 Rotem Yaari 创建并慷慨捐赠。
使用 Sphinx 7.2.6 创建。最后生成文档时间:2024 年 11 月 8 日星期五美国东部时间上午 8:41:19