混合属性¶
在具有 “hybrid” 行为的 ORM 映射类上定义属性。
“hybrid” 表示该属性在类级别和实例级别定义了不同的行为。
混合
扩展提供了一种特殊形式的方法装饰器,并且对 SQLAlchemy 的其余部分的依赖性最小。它的基本作理论适用于任何基于描述符的表达系统。
考虑一个映射 Interval
,表示整数 start
和 end
值。我们可以在生成 SQL 的映射类上定义更高级别的函数
表达式,以及
实例级别。 下面,每个函数都用 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
descriptor 计算给定 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
应用于 attribute 的方法。这些方法返回布尔值,并利用 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"
定义不同于 Attribute 行为的表达式行为¶
在上一节中,我们在 Interval.contains
和 Interval.intersects
方法中使用 &
和 |
位运算符是幸运的,因为我们的函数对两个布尔值进行作以返回一个新的布尔值。在许多情况下,Python 内部函数和 SQLAlchemy SQL 表达式的构造具有足够的差异,因此应该定义两个单独的 Python 表达式。为此,混合
装饰器定义了一个修饰符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
,使用 decorator
@radius.inplace.expression
,它将两个修饰符链接在一起
hybrid_property.inplace
和 hybrid_property.expression
中。使用 hybrid_property.inplace
表示
hybrid_property.expression()
修饰符应就地改变 Interval.radius
处的现有混合对象,而无需创建新对象。有关此修饰符及其基本原理的说明,将在下一节 Using inplace to create compliant pep-484 hybrid properties(使用就地创建符合 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 属性¶
在上一节中,说明了一个 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
进一步限定了
decorator 的 intent 调用,以便不应创建新副本,从而维护
Interval.radius
名称,同时允许其他方法
Interval._radius_setter
和 Interval._radius_expression
的名称不同。
2.0.4 版本中的新功能: 添加了 hybrid_property.inplace
,以允许对复合hybrid_property
对象进行不太详细的构造,同时不必使用重复的方法名称。此外,还允许在 hybrid_property.expression
中使用 @classmethod
,
hybrid_property.update_expression
和
hybrid_property.comparator
允许键入工具识别
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)
方法现在在 set 时调用:
>>> i1 = Interval(5, 10)
>>> i1.length
5
>>> i1.length = 12
>>> i1.end
17
允许批量 ORM 更新¶
混合体可以在使用启用 ORM 的更新时定义自定义的 “UPDATE” 处理程序,从而允许在更新的 SET 子句中使用混合体。
通常,当将 hybrid 与 update()
一起使用时,SQL
expression 用作作为 SET 目标的列。 如果
Interval
类start_point
具有链接到
Interval.start
,这可以直接替换:
from sqlalchemy import update
stmt = update(Interval).values({Interval.start_point: 10})
但是,当使用像 Interval.length
这样的复合混合时,此混合表示多个列。我们可以使用 hybrid_property.update_expression()
装饰器设置一个处理程序,该处理程序将容纳在 VALUES 表达式中传递的值,该值可能会影响此影响。与我们的 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)
此 SET 表达式由 ORM 自动容纳。
另请参阅
启用 ORM 的 INSERT、UPDATE 和 DELETE 语句 - 包括启用 ORM 的 UPDATE 语句的背景信息
使用关系¶
创建与基于列的数据一起使用的混合时,没有本质区别。对不同表达的需求往往更大。我们将说明的两个变体是 “join-dependent” hybrid和 “correlated subquery” hybrid。
连接依赖关系 hybrid¶
请考虑以下将 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,
)
上述混合属性平衡
适用于第一个
SavingsAccount
条目。Python 中的 getter/setter 方法可以将账户
视为 self
上可用的 Python 列表。
提示
上面示例中的 User.balance
getter 访问
self.acccounts
集合,该集合通常通过
selectinload()
加载器策略。
当
relationship()
上未另行说明时,默认加载器策略是 lazyload(),
它按需发出 SQL。使用 asyncio 时,不支持 lazyload()
等按需加载器,因此应注意确保 self.accounts
collection 可供此混合访问器访问。
在表达式级别,预计 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
构建自定义比较器¶
hybrid 属性还包括一个允许构建自定义 parator 的 helper 。比较器对象允许单独自定义每个 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
接口。像小写这样的“强制”运算可以应用于所有比较运算(即 eq
,
lt
、gt
等)使用 Operators.operate():
class CaseInsensitiveComparator(Comparator):
def operate(self, op, other, **kwargs):
return op(
func.lower(self.__clause_element__()),
func.lower(other),
**kwargs,
)
跨子类重用 Hybrid Properties¶
可以从超类中引用 hybrid,以允许修改 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
对象上的同名访问器冲突。要在直接引用父类 Descriptors 时覆盖这些方法,请添加特殊限定符 hybrid_property.overrides
,它将取消引用 instrumented 属性回 hybrid 对象:
class FirstNameLastName(FirstNameOnly):
# ...
last_name: Mapped[str]
@FirstNameOnly.name.overrides.expression
@classmethod
def name(cls):
return func.concat(cls.first_name, " ", cls.last_name)
混合值对象¶
请注意,在前面的示例中,如果我们要比较 word_insensitive
属性
转换为纯 Python 字符串,则
Python 字符串不会被强制为小写 - 该
CaseInsensitiveComparator
返回的
@word_insensitive.comparator
的 SQL 端。
定制比较器的一种更全面的形式是构建一个 Hybrid
value 对象。此方法将目标值或表达式应用于值对象,然后在所有情况下由访问器返回该对象。value 对象允许控制对值的所有作以及如何处理比较值,无论是在 SQL 表达式端还是在 Python 值端。将之前的 CaseInsensitiveComparator
类替换为新的
CaseInsensitiveWord
类:
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 的 “converted”
形式工作,无论是 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 参考¶
对象名称 |
描述 |
---|---|
|
|
|
|
|
|
|
-
类 sqlalchemy.ext.hybrid 中。hybrid_method¶
一个装饰器,允许定义具有实例级和类级行为的 Python 对象方法。
类签名
classsqlalchemy.ext.hybrid.hybrid_method
(sqlalchemy.orm.base.InspectionAttrInfo
,typing.通用
)-
方法sqlalchemy.ext.hybrid.hybrid_method.
__init__(func: Callable[[Concatenate[Any, _P]], _R], expr:Callable[[Concatenate[Any,_P]],SQLCoreOperations[_R]]None=None)¶
创建新hybrid_method
。
通常通过 decorator 进行使用: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)
-
methodsqlalchemy.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.
就地¶
返回此hybrid_method
的就地 mutator。
当hybrid_method.expression()
装饰器被调用时,hybrid_method
类已经执行了 “in place” 更改,因此此属性返回 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()
类签名
类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
。
通常通过 decorator 进行使用: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] ¶
提供定义自定义比较器生成方法的修改装饰器。
装饰方法的返回值应该是比较器
。
注意hybrid_property.comparator()
装饰器 替换了hybrid_property.expression()
装饰。 它们不能一起使用。
在类级别调用 hybrid 时, 这里给出的Comparator
对象被包装在一个专门的QueryableAttribute
中,该对象与 ORM 用来表示其他 Map 属性的对象类型相同。这样做的原因是,其他类级属性(例如文档字符串和对 hybrid 本身的引用)可以在返回的结构中维护,而无需对传入的原始 comparator 对象进行任何修改。
注意
当从拥有类引用混合属性时(例如SomeClass.some_hybrid
)、一个QueryableAttribute
返回,将表达式或比较器对象表示为此混合对象。但是,该对象本身具有名为expression
和比较器
;因此,当尝试在 子类中,可能需要使用hybrid_property.overrides
修饰符。有关详细信息,请参阅该修饰符。
-
方法sqlalchemy.ext.hybrid.hybrid_property.
deleter(fdel: _HybridDeleterType[_T])hybrid_property[_T] ¶
提供定义删除方法的修改修饰器。
-
methodsqlalchemy.ext.hybrid.hybrid_property.
expression(expr: _HybridExprCallableType[_T])hybrid_property[_T] ¶
提供定义 SQL 表达式生成方法的修改修饰器。
当在类级别调用混合时,这里给出的 SQL 表达式被包装在一个专门的QueryableAttribute
中,该对象与 ORM 用来表示其他映射属性的对象类型相同。这样做的原因是,其他类级属性(例如文档字符串和对 hybrid 本身的引用)可以在返回的结构中维护,而无需对传入的原始 SQL 表达式进行任何修改。
注意
当从拥有类引用混合属性时(例如SomeClass.some_hybrid
)、一个QueryableAttribute
返回,表示表达式或比较器对象以及此混合对象。但是,该对象本身具有名为expression
和比较器
;因此,当尝试在 子类中,可能需要使用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.
就地¶
返回此hybrid_property
的就地 mutator。
这是为了允许 hybrid 的就地更改,允许重用特定名称的第一个 hybrid 方法,以便添加更多方法,而不必为这些方法命名相同的方法,例如: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.
覆盖¶
覆盖现有属性的方法的前缀。hybrid_property.overrides
访问器只返回这个混合对象,当在类级别从父类调用它时,将取消引用通常在此级别返回的“instrumented attribute”,并允许修改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 中。比较器¶
允许轻松构建自定义的帮助程序类PropComparator (属性比较器)
用于 Hybrids 的类。
-
类 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'¶
指示InspectionAttr
的符号
分配给InspectionAttr.extension_type
属性。
另请参阅Mapper.all_orm_attributes
-