混合属性
在ORM映射类上定义具有“混合”行为的属性。
“混合”是指属性在类级别和实例级别定义了不同的行为。
这个 hybrid
扩展提供了一种特殊形式的方法修饰器,大约有50行代码,几乎不依赖于其他的sqlacalchemy。理论上,它可以与任何基于描述符的表达式系统一起工作。
考虑映射 Interval
,表示整数 start
和 end
价值观。我们可以在生成类级SQL表达式的映射类上定义更高级别的函数,在实例级定义python表达式计算。下面,每个功能都用 hybrid_method
或 hybrid_property
可能收到 self
作为类的实例,或作为类本身:
from sqlalchemy import Column, Integer from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import Session, aliased from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method Base = declarative_base() class Interval(Base): __tablename__ = 'interval' id = Column(Integer, primary_key=True) start = Column(Integer, nullable=False) end = Column(Integer, nullable=False) def __init__(self, start, end): self.start = start self.end = end @hybrid_property def length(self): return self.end - self.start @hybrid_method def contains(self, point): return (self.start <= point) & (point <= self.end) @hybrid_method def intersects(self, other): 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表达式机制求值时(这里使用 QueryableAttribute.expression
访问器)返回新的SQL表达式::
>>> print(Interval.length.expression) interval."end" - interval.start >>> print(Session().query(Interval).filter(Interval.length > 10)) SELECT interval.id AS interval_id, interval.start AS interval_start, interval."end" AS interval_end FROM interval WHERE interval."end" - interval.start > :param_1
ORM方法,例如 Query.filter_by()
普遍使用 getattr()
要定位属性,也可以与混合属性一起使用:
>>> print(Session().query(Interval).filter_by(length=5)) SELECT interval.id AS interval_id, interval.start AS interval_start, interval."end" AS 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(Session().query(Interval).filter(Interval.contains(15))) SELECT interval.id AS interval_id, interval.start AS interval_start, interval."end" AS interval_end FROM interval WHERE interval.start <= :start_1 AND interval."end" > :end_1 >>> ia = aliased(Interval) >>> print(Session().query(Interval, ia).filter(Interval.intersects(ia))) SELECT interval.id AS interval_id, interval.start AS interval_start, interval."end" AS 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"
定义不同于属性行为的表达式行为
我们使用的 &
和 |
上面的按位运算符很幸运,因为我们的函数对两个布尔值进行了运算,以返回一个新的布尔值。在许多情况下,in-python函数和sqlAlchemy SQL表达式的构造有足够的差异,因此应该定义两个单独的python表达式。这个 hybrid
装饰师定义 hybrid_property.expression()
用于此目的的修饰符。例如,我们将定义间隔的半径,这需要使用绝对值函数:
from sqlalchemy import func class Interval(object): # ... @hybrid_property def radius(self): return abs(self.length) / 2 @radius.expression def radius(cls): return func.abs(cls.length) / 2
在python函数之上 abs()
用于实例级操作,SQL函数 ABS()
是通过 func
类级表达式的对象::
>>> i1.radius 2 >>> print(Session().query(Interval).filter(Interval.radius > 5)) SELECT interval.id AS interval_id, interval.start AS interval_start, interval."end" AS interval_end FROM interval WHERE abs(interval."end" - interval.start) / :abs_1 > :param_1
注解
当为混合属性或方法定义表达式时,表达式方法 must 保留原始混合的名称,否则具有附加状态的新混合将附加到具有不匹配名称的类。要使用上面的示例:
class Interval(object): # ... @hybrid_property def radius(self): return abs(self.length) / 2 # WRONG - the non-matching name will cause this function to be # ignored @radius.expression def radius_expression(cls): return func.abs(cls.length) / 2
这对于其他的变异器方法也是如此,例如 hybrid_property.update_expression()
. 这和 @property
构造它是标准python的一部分。
定义setter
混合属性还可以定义setter方法。如果我们想要 length
上面,设置后修改端点值:
class Interval(object): # ... @hybrid_property def length(self): return self.end - self.start @length.setter def length(self, value): self.end = self.start + value
这个 length(self, value)
方法现在在set:上调用:
>>> i1 = Interval(5, 10) >>> i1.length 5 >>> i1.length = 12 >>> i1.end 17
允许批量更新ORM
当使用 Query.update()
方法,允许在update的set子句中使用混合。
通常,当使用混合动力 Query.update()
,SQL表达式用作作为集合目标的列。如果我们 Interval
班上有一辆混合动力车 start_point
链接到 Interval.start
,可直接替换为:
session.query(Interval).update({Interval.start_point: 10})
但是,当使用类似 Interval.length
,此混合表示多个列。我们可以设置一个处理程序来容纳传递给 Query.update()
可能会影响这一点,使用 hybrid_property.update_expression()
装饰者。与setter类似的处理程序是:
class Interval(object): # ... @hybrid_property def length(self): return self.end - self.start @length.setter def length(self, value): self.end = self.start + value @length.update_expression def length(cls, value): return [ (cls.end, cls.start + value) ]
上面,如果我们使用 Interval.length
在更新表达式中作为:
session.query(Interval).update( {Interval.length: 25}, synchronize_session='fetch')
我们将得到一个更新语句,其行如下:
UPDATE interval SET end=start + :value
在某些情况下,默认的“evaluate”策略不能在python中执行集合表达式;虽然支持上面使用的addition操作符,但是对于更复杂的集合表达式,通常需要使用“fetch”或错误的同步策略,如上图所示。
注解
要使ORM批量更新与混合一起使用,混合的函数名必须与访问它的方式相匹配。这样的事情不会奏效的::
class Interval(object): # ... def _get(self): return self.end - self.start def _set(self, value): self.end = self.start + value def _update_expr(cls, value): return [ (cls.end, cls.start + value) ] length = hybrid_property( fget=_get, fset=_set, update_expr=_update_expr ) The Python descriptor protocol does not provide any reliable way for a descriptor to know what attribute name it was accessed as, and the UPDATE scheme currently relies upon being able to access the attribute from an instance by name in order to perform the instance synchronization step.
1.2 新版功能: 增加了对混合属性批量更新的支持。
处理关系
与基于列的数据相比,创建与相关对象一起工作的混合对象没有本质的区别。对不同表达式的需求往往更大。我们将说明的两种变体是“依赖连接”的混合体和“相关子查询”的混合体。
连接依赖关系混合
考虑下面的声明性映射,它与 User
到A SavingsAccount
::
from sqlalchemy import Column, Integer, ForeignKey, Numeric, String from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.hybrid import hybrid_property Base = declarative_base() class SavingsAccount(Base): __tablename__ = 'account' id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey('user.id'), nullable=False) balance = Column(Numeric(15, 5)) class User(Base): __tablename__ = 'user' id = Column(Integer, primary_key=True) name = Column(String(100), nullable=False) accounts = relationship("SavingsAccount", backref="owner") @hybrid_property def balance(self): if self.accounts: return self.accounts[0].balance else: return None @balance.setter def balance(self, value): if not self.accounts: account = Account(owner=self) else: account = self.accounts[0] account.balance = value @balance.expression def balance(cls): return SavingsAccount.balance
上述混合性质 balance
与第一个 SavingsAccount
此用户的帐户列表中的条目。在python中getter/setter方法可以处理 accounts
作为上提供的python列表 self
.
但是,在表达式级别,应该 User
类将在适当的上下文中使用,以便 SavingsAccount
将出席:
>>> print(Session().query(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 or_ >>> print (Session().query(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级别通常执行得更差。使用相同的技术,如 使用列属性 我们可以调整 SavingsAccount
汇总余额的示例 all 帐户,并对列表达式使用相关的子查询::
from sqlalchemy import Column, Integer, ForeignKey, Numeric, String from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.ext.hybrid import hybrid_property from sqlalchemy import select, func Base = declarative_base() class SavingsAccount(Base): __tablename__ = 'account' id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey('user.id'), nullable=False) balance = Column(Numeric(15, 5)) class User(Base): __tablename__ = 'user' id = Column(Integer, primary_key=True) name = Column(String(100), nullable=False) accounts = relationship("SavingsAccount", backref="owner") @hybrid_property def balance(self): return sum(acc.balance for acc in self.accounts) @balance.expression def balance(cls): return select(func.sum(SavingsAccount.balance)).\ where(SavingsAccount.user_id==cls.id).\ label('total_balance')
上面的食谱会给我们 balance
呈现相关选择的列:
>>> print(s.query(User).filter(User.balance > 400)) SELECT "user".id AS user_id, "user".name AS user_name FROM "user" WHERE (SELECT sum(account.balance) AS sum_1 FROM account WHERE account.user_id = "user".id) > :param_1
构建自定义比较器
Hybrid属性还包括一个助手,它允许构建自定义比较器。Comparator对象允许您分别自定义每个SQLAlchemy表达式运算符的行为。它们在创建自定义类型时非常有用,这些自定义类型在SQL端具有一些非常特殊的行为。
注解
这个 hybrid_property.comparator()
本节介绍的装饰器 替换 使用的 hybrid_property.expression()
装饰者。它们不能一起使用。
下面的示例类允许对名为 word_insensitive
::
from sqlalchemy.ext.hybrid import Comparator, hybrid_property from sqlalchemy import func, Column, Integer, String from sqlalchemy.orm import Session from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class CaseInsensitiveComparator(Comparator): def __eq__(self, other): return func.lower(self.__clause_element__()) == func.lower(other) class SearchWord(Base): __tablename__ = 'searchword' id = Column(Integer, primary_key=True) word = Column(String(255), nullable=False) @hybrid_property def word_insensitive(self): return self.word.lower() @word_insensitive.comparator def word_insensitive(cls): return CaseInsensitiveComparator(cls.word)
上面的SQL表达式 word_insensitive
将应用 LOWER()
两边的SQL函数:
>>> print(Session().query(SearchWord).filter_by(word_insensitive="Trucks")) SELECT searchword.id AS searchword_id, searchword.word AS searchword_word FROM searchword WHERE lower(searchword.word) = lower(:lower_1)
这个 CaseInsensitiveComparator
上面实现了 ColumnOperators
接口。“强制”操作(如lowercasing)可应用于所有比较操作(即 eq
, lt
, gt
等)使用 Operators.operate()
::
class CaseInsensitiveComparator(Comparator): def operate(self, op, other): return op(func.lower(self.__clause_element__()), func.lower(other))
跨子类重用混合属性
一个混合可以从一个超类中引用,以允许修改诸如 hybrid_property.getter()
, hybrid_property.setter()
用于在子类上重新定义这些方法。这类似于标准的python @property
对象作品:
class FirstNameOnly(Base): # ... first_name = Column(String) @hybrid_property def name(self): return self.first_name @name.setter def name(self, value): self.first_name = value class FirstNameLastName(FirstNameOnly): # ... last_name = Column(String) @FirstNameOnly.name.getter def name(self): return self.first_name + ' ' + self.last_name @name.setter def name(self, value): 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 = Column(String) @FirstNameOnly.name.overrides.expression def name(cls): return func.concat(cls.first_name, ' ', cls.last_name)
1.2 新版功能: 补充 hybrid_property.getter()
以及根据子类重新定义访问器的能力。
混合值对象
注意在前面的示例中,如果要比较 word_insensitive
的属性 SearchWord
实例到一个普通的python字符串,普通的python字符串不会被强制为小写- CaseInsensitiveComparator
我们建造,由 @word_insensitive.comparator
,仅适用于SQL端。
自定义比较器的一种更全面的形式是构造 混合值对象 . 此技术将目标值或表达式应用于值对象,然后由访问器在所有情况下返回该对象。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): if not isinstance(other, CaseInsensitiveWord): other = CaseInsensitiveWord(other) return op(self.word, other.word) 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 = Column(Integer, primary_key=True) word = Column(String(255), nullable=False) @hybrid_property def word_insensitive(self): return CaseInsensitiveWord(self.word)
这个 word_insensitive
属性现在普遍具有不区分大小写的比较行为,包括SQL表达式与Python表达式(注意,这里的python值被转换为小写):
>>> print(Session().query(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表达式:
>>> sw1 = aliased(SearchWord) >>> sw2 = aliased(SearchWord) >>> print(Session().query( ... 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
混合值模式对于任何可能具有多种表示形式的值都非常有用,例如时间戳、时间增量、度量单位、货币和加密密码。
参见
Hybrids and Value Agnostic Types -在techpot.zzzeek.org博客上
Value Agnostic Types, Part II -在techpot.zzzeek.org博客上
建筑变压器
A 变压器 是一个可以接收 Query
对象并返回新的。这个 Query
对象包含一个方法 with_transformation()
它返回一个新的 Query
由给定函数转换。
我们可以把这个和 Comparator
类来生成一种类型的配方,既可以设置查询的FROM子句,也可以指定筛选条件。
考虑映射类 Node
,它使用邻接列表组装成层次树模式:
from sqlalchemy import Column, Integer, ForeignKey from sqlalchemy.orm import relationship from sqlalchemy.ext.declarative import declarative_base Base = declarative_base() class Node(Base): __tablename__ = 'node' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('node.id')) parent = relationship("Node", remote_side=id)
假设我们想添加一个访问器 grandparent
. 这将返回 parent
属于 Node.parent
. 当我们有一个 Node
,这很简单:
from sqlalchemy.ext.hybrid import hybrid_property class Node(Base): # ... @hybrid_property def grandparent(self): return self.parent.parent
在表达上,事情并不那么清楚。我们需要建造一个 Query
我们在哪里 Query.join()
两次沿着 Node.parent
到达 grandparent
. 我们可以返回一个转换可调用文件,并将其与 Comparator
类接收任何 Query
对象,并返回一个新的 Node.parent
属性并根据给定条件进行筛选:
from sqlalchemy.ext.hybrid import Comparator class GrandparentTransformer(Comparator): def operate(self, op, other): def transform(q): cls = self.__clause_element__() parent_alias = aliased(cls) return q.join(parent_alias, cls.parent).\ filter(op(parent_alias.parent, other)) return transform Base = declarative_base() class Node(Base): __tablename__ = 'node' id = Column(Integer, primary_key=True) parent_id = Column(Integer, ForeignKey('node.id')) parent = relationship("Node", remote_side=id) @hybrid_property def grandparent(self): return self.parent.parent @grandparent.comparator def grandparent(cls): return GrandparentTransformer(cls)
这个 GrandparentTransformer
超越核心 Operators.operate()
方法的基础 Comparator
返回查询转换可调用的层次结构,然后在特定上下文中运行给定的比较操作。例如,在上面的示例中, operate
方法被调用,给定 Operators.eq
可调用以及比较的右侧 Node(id=5)
. 函数 transform
然后返回,它将转换 Query
第一个加入 Node.parent
,然后比较 parent_alias
使用 Operators.eq
向左右两侧传球 Query.filter()
:
>>> from sqlalchemy.orm import Session >>> session = Session() sql>>> session.query(Node).\ ... with_transformation(Node.grandparent==Node(id=5)).\ ... all() SELECT node.id AS node_id, node.parent_id AS node_parent_id FROM node JOIN node AS node_1 ON node_1.id = node.parent_id WHERE :param_1 = node_1.parent_id
我们可以通过将“join”步骤与“filter”步骤分离,将模式修改为更详细但更灵活。这里棘手的部分是确保 GrandparentTransformer
使用相同的 AliasedClass
反对对象 Node
. 下面我们使用一种简单的记忆方法,将 GrandparentTransformer
每节课:
class Node(Base): # ... @grandparent.comparator def grandparent(cls): # memoize a GrandparentTransformer # per class if '_gp' not in cls.__dict__: cls._gp = GrandparentTransformer(cls) return cls._gp class GrandparentTransformer(Comparator): def __init__(self, cls): self.parent_alias = aliased(cls) @property def join(self): def go(q): return q.join(self.parent_alias, Node.parent) return go def operate(self, op, other): return op(self.parent_alias.parent, other)
sql>>> session.query(Node).\ ... with_transformation(Node.grandparent.join).\ ... filter(Node.grandparent==Node(id=5)) SELECT node.id AS node_id, node.parent_id AS node_parent_id FROM node JOIN node AS node_1 ON node_1.id = node.parent_id WHERE :param_1 = node_1.parent_id
“Transformer”模式是一种实验模式,它开始使用一些函数式编程模式。虽然它只推荐给高级和/或病患开发人员,但可能有很多神奇的东西可以使用。
API引用
Object Name | Description |
---|---|
允许轻松构造自定义 | |
一个允许定义具有实例级和类级行为的Python对象方法的修饰器。 | |
符号表示 | |
允许定义具有实例级和类级行为的python描述符的修饰器。 | |
- class sqlalchemy.ext.hybrid.hybrid_method(func, expr=None)¶
一个允许定义具有实例级和类级行为的Python对象方法的修饰器。
类签名
class
sqlalchemy.ext.hybrid.hybrid_method
(sqlalchemy.orm.base.InspectionAttrInfo
)- method
sqlalchemy.ext.hybrid.hybrid_method.
__init__(func, expr=None)¶ 创建新的
hybrid_method
.通常通过装饰器使用:
from sqlalchemy.ext.hybrid import hybrid_method class SomeClass(object): @hybrid_method def value(self, x, y): return self._value + x + y @value.expression def value(self, x, y): return func.some_function(self._value, x, y)
- method
sqlalchemy.ext.hybrid.hybrid_method.
expression(expr)¶ 提供定义SQL表达式生成方法的修改修饰符。
- attribute
sqlalchemy.ext.hybrid.hybrid_method.
extension_type = symbol('HYBRID_METHOD')¶ 分机类型(如果有)。默认为
NOT_EXTENSION
参见
- method
- class sqlalchemy.ext.hybrid.hybrid_property(fget, fset=None, fdel=None, expr=None, custom_comparator=None, update_expr=None)¶
允许定义具有实例级和类级行为的python描述符的修饰器。
类签名
class
sqlalchemy.ext.hybrid.hybrid_property
(sqlalchemy.orm.base.InspectionAttrInfo
)- method
sqlalchemy.ext.hybrid.hybrid_property.
__init__(fget, fset=None, fdel=None, expr=None, custom_comparator=None, update_expr=None)¶ 创建新的
hybrid_property
.通常通过装饰器使用:
from sqlalchemy.ext.hybrid import hybrid_property class SomeClass(object): @hybrid_property def value(self): return self._value @value.setter def value(self, value): self._value = value
- method
sqlalchemy.ext.hybrid.hybrid_property.
comparator(comparator)¶ 提供定义自定义比较器生成方法的修改修饰器。
修饰方法的返回值应该是
Comparator
.注解
这个
hybrid_property.comparator()
decorator 替换 使用的hybrid_property.expression()
装饰者。它们不能一起使用。当在类级别调用混合时,
Comparator
这里给出的对象被包装在一个专用的QueryableAttribute
,这是ORM用来表示其他映射属性的同一类对象。这样做的原因是,可以在返回的结构中维护其他类级属性(如docstrings和对混合体本身的引用),而不必修改传入的原始comparator对象。注解
当提到一个拥有类的混合财产时(例如。
SomeClass.some_hybrid
)的实例QueryableAttribute
返回,将表达式或比较器对象表示为此混合对象。但是,该对象本身具有调用的访问器expression
和comparator
;因此,当尝试在子类上重写这些修饰符时,可能需要使用hybrid_property.overrides
先修改。有关详细信息,请参阅该修饰符。
- method
sqlalchemy.ext.hybrid.hybrid_property.
deleter(fdel)¶ 提供定义删除方法的修改修饰符。
- method
sqlalchemy.ext.hybrid.hybrid_property.
expression(expr)¶ 提供定义SQL表达式生成方法的修改修饰符。
当在类级别调用混合时,此处给出的SQL表达式包装在专用的
QueryableAttribute
,这是ORM用来表示其他映射属性的同一类对象。这样做的原因是,可以在返回的结构中维护其他类级属性(如docstrings和对混合体本身的引用),而不修改传入的原始SQL表达式。注解
当提到一个拥有类的混合财产时(例如。
SomeClass.some_hybrid
)的实例QueryableAttribute
返回,表示表达式或比较器对象以及此混合对象。但是,该对象本身具有调用的访问器expression
和comparator
;因此,当尝试在子类上重写这些修饰符时,可能需要使用hybrid_property.overrides
先修改。有关详细信息,请参阅该修饰符。参见
- attribute
sqlalchemy.ext.hybrid.hybrid_property.
extension_type = symbol('HYBRID_PROPERTY')¶ 分机类型(如果有)。默认为
NOT_EXTENSION
参见
- method
sqlalchemy.ext.hybrid.hybrid_property.
getter(fget)¶ 提供定义getter方法的修改修饰符。
1.2 新版功能.
- attribute
sqlalchemy.ext.hybrid.hybrid_property.
overrides¶ 覆盖现有属性的方法的前缀。
这个
hybrid_property.overrides
访问器只返回这个混合对象,当从父类的类级别调用这个混合对象时,它将取消引用通常在此级别返回的“instructed attribute”,并允许修改类似hybrid_property.expression()
和hybrid_property.comparator()
在不与通常存在于QueryableAttribute
::class SuperClass(object): # ... @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 新版功能.
参见
- method
sqlalchemy.ext.hybrid.hybrid_property.
setter(fset)¶ 提供定义setter方法的修改修饰符。
- method
sqlalchemy.ext.hybrid.hybrid_property.
update_expression(meth)¶ 提供定义更新元组生成方法的修改修饰符。
方法接受单个值,该值是要呈现到UPDATE语句的SET子句中的值。然后,该方法应将该值处理为适合于ultimate 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 新版功能.
- method
- class sqlalchemy.ext.hybrid.Comparator(expression)¶
允许轻松构造自定义
PropComparator
用于混血儿的类。类签名
class
sqlalchemy.ext.hybrid.Comparator
(sqlalchemy.orm.PropComparator
)
- sqlalchemy.ext.hybrid.HYBRID_METHOD = symbol('HYBRID_METHOD')¶
符号表示
InspectionAttr
那是类型的hybrid_method
.分配给
InspectionAttr.extension_type
属性。参见
Mapper.all_orm_attributes
- sqlalchemy.ext.hybrid.HYBRID_PROPERTY = symbol('HYBRID_PROPERTY')¶
- 符号表示
InspectionAttr
那是 类型的
hybrid_method
.
分配给
InspectionAttr.extension_type
属性。参见
Mapper.all_orm_attributes
- 符号表示