SqlAlchemy 2.0 中文文档(二十九)(1)

简介: SqlAlchemy 2.0 中文文档(二十九)


原文:docs.sqlalchemy.org/en/20/contents.html

关联代理

原文:docs.sqlalchemy.org/en/20/orm/extensions/associationproxy.html

associationproxy 用于在关系之间创建目标属性的读/写视图。它实质上隐藏了两个端点之间的“中间”属性的使用,并且可以用于从相关对象的集合或标量关系中挑选字段,或者减少使用关联对象模式时的冗长性。创造性地应用,关联代理允许构建复杂的集合和字典视图,几乎可以对任何几何形状进行持久化,使用标准、透明配置的关系模式保存到数据库中。

简化标量集合

考虑两个类UserKeyword之间的多对多映射。每个User可以拥有任意数量的Keyword对象,反之亦然(多对多模式在 Many To Many 中有描述)。下面的示例以相同的方式说明了这种模式,唯一的区别是在User类中添加了一个额外的属性User.keywords

from __future__ import annotations
from typing import Final
from typing import List
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.associationproxy import AssociationProxy
class Base(DeclarativeBase):
    pass
class User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(64))
    kw: Mapped[List[Keyword]] = relationship(secondary=lambda: user_keyword_table)
    def __init__(self, name: str):
        self.name = name
    # proxy the 'keyword' attribute from the 'kw' relationship
    keywords: AssociationProxy[List[str]] = association_proxy("kw", "keyword")
class Keyword(Base):
    __tablename__ = "keyword"
    id: Mapped[int] = mapped_column(primary_key=True)
    keyword: Mapped[str] = mapped_column(String(64))
    def __init__(self, keyword: str):
        self.keyword = keyword
user_keyword_table: Final[Table] = Table(
    "user_keyword",
    Base.metadata,
    Column("user_id", Integer, ForeignKey("user.id"), primary_key=True),
    Column("keyword_id", Integer, ForeignKey("keyword.id"), primary_key=True),
)

在上面的示例中,association_proxy()应用于User类,以生成kw关系的“视图”,该视图公开与每个Keyword对象关联的.keyword的字符串值。当向集合添加字符串时,它还会透明地创建新的Keyword对象:

>>> user = User("jek")
>>> user.keywords.append("cheese-inspector")
>>> user.keywords.append("snack-ninja")
>>> print(user.keywords)
['cheese-inspector', 'snack-ninja']

要理解这一点的机制,首先回顾一下在不使用.keywords关联代理的情况下,UserKeyword的行为。通常,阅读和操作与User关联的“keyword”字符串集合需要从每个集合元素遍历到.keyword属性,这可能很麻烦。下面的示例说明了在不使用关联代理的情况下应用相同系列操作的情况:

>>> # identical operations without using the association proxy
>>> user = User("jek")
>>> user.kw.append(Keyword("cheese-inspector"))
>>> user.kw.append(Keyword("snack-ninja"))
>>> print([keyword.keyword for keyword in user.kw])
['cheese-inspector', 'snack-ninja']

association_proxy()函数生成的AssociationProxy对象是Python 描述符的一个实例,并且不被Mapper以任何方式视为“映射”。因此,无论是使用声明式还是命令式映射,它始终内联显示在映射类的类定义中。

代理通过对操作响应中的底层映射属性或集合进行操作,通过代理进行的更改立即反映在映射属性中,反之亦然。底层属性仍然完全可访问。

当第一次访问时,关联代理对目标集合执行内省操作,以便其行为正确对应。细节,例如本地代理的属性是否是集合(通常情况下是这样)或标量引用,以及集合是否像集合、列表或字典一样行事,都被考虑在内,这样代理应该像底层集合或属性一样行事。

创造新价值

当一个列表 append() 事件(或集合 add(),字典 __setitem__(),或标量赋值事件)被关联代理拦截时,它使用它的构造函数实例化一个新的“中间”对象实例,将给定值作为单个参数传递。在我们上面的示例中,一个像这样的操作:

user.keywords.append("cheese-inspector")

被关联代理翻译成以下操作:

user.kw.append(Keyword("cheese-inspector"))

此示例有效的原因在于我们已经设计了 Keyword 的构造函数以接受一个单一的位置参数 keyword。对于那些不可行的单参数构造函数的情况,关联代理的创建行为可以使用 association_proxy.creator 参数进行自定义,该参数引用了一个可调用对象(即 Python 函数),该对象将根据单一参数产生一个新的对象实例。下面我们使用一个典型的 lambda 函数来说明这一点:

class User(Base):
    ...
    # use Keyword(keyword=kw) on append() events
    keywords: AssociationProxy[List[str]] = association_proxy(
        "kw", "keyword", creator=lambda kw: Keyword(keyword=kw)
    )

当一个基于列表或集合的集合,或者是一个标量属性的情况下,creator 函数接受一个参数。在基于字典的集合的情况下,它接受两个参数,“key” 和 “value”。下面是一个示例,代理到基于字典的集合。

简化关联对象

“关联对象”模式是一种扩展形式的多对多关系,并在关联对象中描述。关联代理对于在常规使用过程中使“关联对象”保持不受干扰是很有用的。

假设我们上面的 user_keyword 表有额外的列,我们希望显式地映射这些列,但在大多数情况下,我们不需要直接访问这些属性。下面,我们展示了一个新的映射,介绍了 UserKeywordAssociation 类,它映射到上面展示的 user_keyword 表。这个类添加了一个额外的列 special_key,这个值我们偶尔想要访问,但不是在通常情况下。我们在 User 类上创建了一个名为 keywords 的关联代理,它将弥合从 Useruser_keyword_associations 集合到每个 UserKeywordAssociation 上的 .keyword 属性的差距:

from __future__ import annotations
from typing import List
from typing import Optional
from sqlalchemy import ForeignKey
from sqlalchemy import String
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.associationproxy import AssociationProxy
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 User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(64))
    user_keyword_associations: Mapped[List[UserKeywordAssociation]] = relationship(
        back_populates="user",
        cascade="all, delete-orphan",
    )
    # association proxy of "user_keyword_associations" collection
    # to "keyword" attribute
    keywords: AssociationProxy[List[Keyword]] = association_proxy(
        "user_keyword_associations",
        "keyword",
        creator=lambda keyword_obj: UserKeywordAssociation(keyword=keyword_obj),
    )
    def __init__(self, name: str):
        self.name = name
class UserKeywordAssociation(Base):
    __tablename__ = "user_keyword"
    user_id: Mapped[int] = mapped_column(ForeignKey("user.id"), primary_key=True)
    keyword_id: Mapped[int] = mapped_column(ForeignKey("keyword.id"), primary_key=True)
    special_key: Mapped[Optional[str]] = mapped_column(String(50))
    user: Mapped[User] = relationship(back_populates="user_keyword_associations")
    keyword: Mapped[Keyword] = relationship()
class Keyword(Base):
    __tablename__ = "keyword"
    id: Mapped[int] = mapped_column(primary_key=True)
    keyword: Mapped[str] = mapped_column("keyword", String(64))
    def __init__(self, keyword: str):
        self.keyword = keyword
    def __repr__(self) -> str:
        return f"Keyword({self.keyword!r})"

通过上述配置,我们可以操作每个 User 对象的 .keywords 集合,其中每个对象都公开了从底层 UserKeywordAssociation 元素获取的 Keyword 对象集合:

>>> user = User("log")
>>> for kw in (Keyword("new_from_blammo"), Keyword("its_big")):
...     user.keywords.append(kw)
>>> print(user.keywords)
[Keyword('new_from_blammo'), Keyword('its_big')]

此示例与先前在 Simplifying Scalar Collections 中说明的示例形成对比,后者的关联代理公开了一个字符串集合,而不是一个组合对象集合。在这种情况下,每个.keywords.append()操作等效于:

>>> user.user_keyword_associations.append(
...     UserKeywordAssociation(keyword=Keyword("its_heavy"))
... )

UserKeywordAssociation对象有两个属性,两者都在关联代理的append()操作的范围内填充;.keyword指的是Keyword对象,.user指的是User对象。.keyword属性首先填充,因为关联代理响应于.append()操作生成新的UserKeywordAssociation对象,将给定的Keyword实例分配给.keyword属性。然后,随着UserKeywordAssociation对象附加到User.user_keyword_associations集合,针对User.user_keyword_associationsback_populates配置的UserKeywordAssociation.user属性在给定的UserKeywordAssociation实例上进行初始化,以指向接收附加操作的父User。上面的special_key参数保持其默认值为None

对于那些我们确实希望special_key具有值的情况,我们明确创建UserKeywordAssociation对象。在下面,我们分配了所有三个属性,其中在构造过程中分配.user的效果是将新的UserKeywordAssociation附加到User.user_keyword_associations集合(通过关系):

>>> UserKeywordAssociation(
...     keyword=Keyword("its_wood"), user=user, special_key="my special key"
... )

关联代理将以这些操作代表的Keyword对象集合返回给我们:

>>> print(user.keywords)
[Keyword('new_from_blammo'), Keyword('its_big'), Keyword('its_heavy'), Keyword('its_wood')]

代理到基于字典的集合

关联代理也可以代理到基于字典的集合。SQLAlchemy 映射通常使用attribute_keyed_dict()集合类型来创建字典集合,以及 Custom Dictionary-Based Collections 中描述的扩展技术。

当检测到基于字典的集合的使用时,关联代理会调整其行为。当新值添加到字典时,关联代理通过将两个参数传递给创建函数来实例化中间对象,而不是一个,即键和值。与往常一样,此创建函数默认为中间类的构造函数,并且可以使用creator参数进行定制。

下面,我们修改了我们的UserKeywordAssociation示例,以便User.user_keyword_associations集合现在将使用字典映射,其中UserKeywordAssociation.special_key参数将用作字典的键。我们还对User.keywords代理应用了一个creator参数,以便在将新元素添加到字典时适当地分配这些值:

from __future__ import annotations
from typing import Dict
from sqlalchemy import ForeignKey
from sqlalchemy import String
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.associationproxy import AssociationProxy
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy.orm.collections import attribute_keyed_dict
class Base(DeclarativeBase):
    pass
class User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(64))
    # user/user_keyword_associations relationship, mapping
    # user_keyword_associations with a dictionary against "special_key" as key.
    user_keyword_associations: Mapped[Dict[str, UserKeywordAssociation]] = relationship(
        back_populates="user",
        collection_class=attribute_keyed_dict("special_key"),
        cascade="all, delete-orphan",
    )
    # proxy to 'user_keyword_associations', instantiating
    # UserKeywordAssociation assigning the new key to 'special_key',
    # values to 'keyword'.
    keywords: AssociationProxy[Dict[str, Keyword]] = association_proxy(
        "user_keyword_associations",
        "keyword",
        creator=lambda k, v: UserKeywordAssociation(special_key=k, keyword=v),
    )
    def __init__(self, name: str):
        self.name = name
class UserKeywordAssociation(Base):
    __tablename__ = "user_keyword"
    user_id: Mapped[int] = mapped_column(ForeignKey("user.id"), primary_key=True)
    keyword_id: Mapped[int] = mapped_column(ForeignKey("keyword.id"), primary_key=True)
    special_key: Mapped[str]
    user: Mapped[User] = relationship(
        back_populates="user_keyword_associations",
    )
    keyword: Mapped[Keyword] = relationship()
class Keyword(Base):
    __tablename__ = "keyword"
    id: Mapped[int] = mapped_column(primary_key=True)
    keyword: Mapped[str] = mapped_column(String(64))
    def __init__(self, keyword: str):
        self.keyword = keyword
    def __repr__(self) -> str:
        return f"Keyword({self.keyword!r})"

我们将.keywords集合表示为一个字典,将UserKeywordAssociation.special_key值映射到Keyword对象:

>>> user = User("log")
>>> user.keywords["sk1"] = Keyword("kw1")
>>> user.keywords["sk2"] = Keyword("kw2")
>>> print(user.keywords)
{'sk1': Keyword('kw1'), 'sk2': Keyword('kw2')}
```## 复合关联代理
鉴于我们之前关于从关系到标量属性的代理、跨关联对象的代理以及代理字典的示例,我们可以将所有三种技术结合起来,为`User`提供一个严格处理`special_key`字符串值映射到`keyword`字符串的`keywords`字典。`UserKeywordAssociation`和`Keyword`类完全被隐藏。这是通过在`User`上建立一个关联到`UserKeywordAssociation`上存在的关联代理来实现的:
```py
from __future__ import annotations
from sqlalchemy import ForeignKey
from sqlalchemy import String
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.associationproxy import AssociationProxy
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
from sqlalchemy.orm.collections import attribute_keyed_dict
class Base(DeclarativeBase):
    pass
class User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(64))
    user_keyword_associations: Mapped[Dict[str, UserKeywordAssociation]] = relationship(
        back_populates="user",
        collection_class=attribute_keyed_dict("special_key"),
        cascade="all, delete-orphan",
    )
    # the same 'user_keyword_associations'->'keyword' proxy as in
    # the basic dictionary example.
    keywords: AssociationProxy[Dict[str, str]] = association_proxy(
        "user_keyword_associations",
        "keyword",
        creator=lambda k, v: UserKeywordAssociation(special_key=k, keyword=v),
    )
    def __init__(self, name: str):
        self.name = name
class UserKeywordAssociation(Base):
    __tablename__ = "user_keyword"
    user_id: Mapped[int] = mapped_column(ForeignKey("user.id"), primary_key=True)
    keyword_id: Mapped[int] = mapped_column(ForeignKey("keyword.id"), primary_key=True)
    special_key: Mapped[str] = mapped_column(String(64))
    user: Mapped[User] = relationship(
        back_populates="user_keyword_associations",
    )
    # the relationship to Keyword is now called
    # 'kw'
    kw: Mapped[Keyword] = relationship()
    # 'keyword' is changed to be a proxy to the
    # 'keyword' attribute of 'Keyword'
    keyword: AssociationProxy[Dict[str, str]] = association_proxy("kw", "keyword")
class Keyword(Base):
    __tablename__ = "keyword"
    id: Mapped[int] = mapped_column(primary_key=True)
    keyword: Mapped[str] = mapped_column(String(64))
    def __init__(self, keyword: str):
        self.keyword = keyword

User.keywords 现在是一个字符串到字符串的字典,UserKeywordAssociationKeyword对象会透明地为我们创建和删除,使用关联代理。在下面的示例中,我们展示了赋值运算符的使用,也由关联代理适当处理,一次将字典值应用到集合中:

>>> user = User("log")
>>> user.keywords = {"sk1": "kw1", "sk2": "kw2"}
>>> print(user.keywords)
{'sk1': 'kw1', 'sk2': 'kw2'}
>>> user.keywords["sk3"] = "kw3"
>>> del user.keywords["sk2"]
>>> print(user.keywords)
{'sk1': 'kw1', 'sk3': 'kw3'}
>>> # illustrate un-proxied usage
... print(user.user_keyword_associations["sk3"].kw)
<__main__.Keyword object at 0x12ceb90>

我们上面示例的一个注意事项是,由于为每个字典设置操作创建了Keyword对象,所以示例未能保持Keyword对象在其字符串名称上的唯一性,这是像这种标记场景的典型要求。对于这种用例,建议使用UniqueObject这个配方,或类似的创建策略,它将应用“先查找,然后创建”策略到Keyword类的构造函数,以便如果给定名称已经存在,则返回已经存在的Keyword

使用关联代理进行查询

AssociationProxy 具有简单的 SQL 构建能力,类似于其他 ORM 映射属性在类级别上的工作方式,并且基本上基于 SQL EXISTS 关键字提供了基本的过滤支持。

注意

关联代理扩展的主要目的是允许改进已加载的映射对象实例的持久性和对象访问模式。类绑定查询功能的用途有限,并且不会取代在构建具有 JOINs、急加载选项等 SQL 查询时需要引用底层属性的需求。

对于本节,假设一个类既有一个关联到列的关联代理,又有一个关联到相关对象的关联代理,就像下面的映射示例一样:

from __future__ import annotations
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy
from sqlalchemy.orm import DeclarativeBase, relationship
from sqlalchemy.orm.collections import attribute_keyed_dict
from sqlalchemy.orm.collections import Mapped
class Base(DeclarativeBase):
    pass
class User(Base):
    __tablename__ = "user"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(64))
    user_keyword_associations: Mapped[UserKeywordAssociation] = relationship(
        cascade="all, delete-orphan",
    )
    # object-targeted association proxy
    keywords: AssociationProxy[List[Keyword]] = association_proxy(
        "user_keyword_associations",
        "keyword",
    )
    # column-targeted association proxy
    special_keys: AssociationProxy[List[str]] = association_proxy(
        "user_keyword_associations", "special_key"
    )
class UserKeywordAssociation(Base):
    __tablename__ = "user_keyword"
    user_id: Mapped[int] = mapped_column(ForeignKey("user.id"), primary_key=True)
    keyword_id: Mapped[int] = mapped_column(ForeignKey("keyword.id"), primary_key=True)
    special_key: Mapped[str] = mapped_column(String(64))
    keyword: Mapped[Keyword] = relationship()
class Keyword(Base):
    __tablename__ = "keyword"
    id: Mapped[int] = mapped_column(primary_key=True)
    keyword: Mapped[str] = mapped_column(String(64))

生成的 SQL 采用了针对 EXISTS SQL 操作符的相关子查询的形式,以便在不需要对封闭查询进行额外修改的情况下在 WHERE 子句中使用。如果关联代理的直接目标是一个映射的列表达式,则可以使用标准列操作符,这些操作符将嵌入到子查询中。例如,一个直接的等式操作符:

>>> print(session.scalars(select(User).where(User.special_keys == "jek")))
SELECT  "user".id  AS  user_id,  "user".name  AS  user_name
FROM  "user"
WHERE  EXISTS  (SELECT  1
FROM  user_keyword
WHERE  "user".id  =  user_keyword.user_id  AND  user_keyword.special_key  =  :special_key_1) 

一个 LIKE 操作符:

>>> print(session.scalars(select(User).where(User.special_keys.like("%jek"))))
SELECT  "user".id  AS  user_id,  "user".name  AS  user_name
FROM  "user"
WHERE  EXISTS  (SELECT  1
FROM  user_keyword
WHERE  "user".id  =  user_keyword.user_id  AND  user_keyword.special_key  LIKE  :special_key_1) 

对于关联代理,其直接目标是相关对象或集合,或相关对象上的另一个关联代理或属性的情况,可以使用关系导向操作符,如 PropComparator.has()PropComparator.any()User.keywords 属性实际上是两个链接在一起的关联代理,因此在使用此代理生成 SQL 短语时,我们得到两个级别的 EXISTS 子查询:

>>> print(session.scalars(select(User).where(User.keywords.any(Keyword.keyword == "jek"))))
SELECT  "user".id  AS  user_id,  "user".name  AS  user_name
FROM  "user"
WHERE  EXISTS  (SELECT  1
FROM  user_keyword
WHERE  "user".id  =  user_keyword.user_id  AND  (EXISTS  (SELECT  1
FROM  keyword
WHERE  keyword.id  =  user_keyword.keyword_id  AND  keyword.keyword  =  :keyword_1))) 

这不是 SQL 的最有效形式,因此,虽然关联代理可以方便快速生成 WHERE 条件,但应该检查 SQL 结果,并将其“展开”为明确的 JOIN 条件以获得最佳效果,特别是在将关联代理链接在一起时。

在 1.3 版更改:根据目标类型,关联代理功能提供了不同的查询模式。请参阅 关联代理现在为面向列的目标提供标准列操作符。

级联标量删除

1.3 版中的新功能。

给定一个映射如下:

from __future__ import annotations
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.ext.associationproxy import association_proxy, AssociationProxy
from sqlalchemy.orm import DeclarativeBase, relationship
from sqlalchemy.orm.collections import attribute_keyed_dict
from sqlalchemy.orm.collections import Mapped
class Base(DeclarativeBase):
    pass
class A(Base):
    __tablename__ = "test_a"
    id: Mapped[int] = mapped_column(primary_key=True)
    ab: Mapped[AB] = relationship(uselist=False)
    b: AssociationProxy[B] = association_proxy(
        "ab", "b", creator=lambda b: AB(b=b), cascade_scalar_deletes=True
    )
class B(Base):
    __tablename__ = "test_b"
    id: Mapped[int] = mapped_column(primary_key=True)
class AB(Base):
    __tablename__ = "test_ab"
    a_id: Mapped[int] = mapped_column(ForeignKey(A.id), primary_key=True)
    b_id: Mapped[int] = mapped_column(ForeignKey(B.id), primary_key=True)
    b: Mapped[B] = relationship()

A.b 的赋值将生成一个 AB 对象:

a.b = B()

A.b 关联是标量的,并包括使用参数 AssociationProxy.cascade_scalar_deletes。当启用此参数时,将 A.b 设置为 None 将同时移除 A.ab

a.b = None
assert a.ab is None

当未设置 AssociationProxy.cascade_scalar_deletes 时,上述关联对象 a.ab 将保持不变。

请注意,这不是针对基于集合的关联代理的行为;在这种情况下,当删除代理集合的成员时,中间关联对象总是被移除。是否删除行取决于关系级联设置。

另请参阅

级联

标量关系

下面的示例说明了在一对多关系的多方上使用关联代理,访问标量对象的属性:

from __future__ import annotations
from typing import List
from sqlalchemy import ForeignKey
from sqlalchemy import String
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy.ext.associationproxy import AssociationProxy
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 Recipe(Base):
    __tablename__ = "recipe"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(64))
    steps: Mapped[List[Step]] = relationship(back_populates="recipe")
    step_descriptions: AssociationProxy[List[str]] = association_proxy(
        "steps", "description"
    )
class Step(Base):
    __tablename__ = "step"
    id: Mapped[int] = mapped_column(primary_key=True)
    description: Mapped[str]
    recipe_id: Mapped[int] = mapped_column(ForeignKey("recipe.id"))
    recipe: Mapped[Recipe] = relationship(back_populates="steps")
    recipe_name: AssociationProxy[str] = association_proxy("recipe", "name")
    def __init__(self, description: str) -> None:
        self.description = description
my_snack = Recipe(
    name="afternoon snack",
    step_descriptions=[
        "slice bread",
        "spread peanut butted",
        "eat sandwich",
    ],
)

可以使用以下方式打印 my_snack 的步骤摘要:

>>> for i, step in enumerate(my_snack.steps, 1):
...     print(f"Step {i} of {step.recipe_name!r}: {step.description}")
Step 1 of 'afternoon snack': slice bread
Step 2 of 'afternoon snack': spread peanut butted
Step 3 of 'afternoon snack': eat sandwich

API 文档

对象名称 描述
association_proxy(target_collection, attr, *, [creator, getset_factory, proxy_factory, proxy_bulk_set, info, cascade_scalar_deletes, create_on_none_assignment, init, repr, default, default_factory, compare, kw_only]) 返回一个实现对目标属性的视图的 Python 属性,该属性引用目标对象的成员上的属性。
AssociationProxy 一个描述符,提供对象属性的读写视图。
AssociationProxyExtensionType 一个枚举。
AssociationProxyInstance 一个每个类的对象,提供类和对象特定的结果。
ColumnAssociationProxyInstance 一个AssociationProxyInstance,它具有数据库列作为目标。
ObjectAssociationProxyInstance 一个AssociationProxyInstance,它具有一个对象作为目标。
function sqlalchemy.ext.associationproxy.association_proxy(target_collection: str, attr: str, *, creator: _CreatorProtocol | None = None, getset_factory: _GetSetFactoryProtocol | None = None, proxy_factory: _ProxyFactoryProtocol | None = None, proxy_bulk_set: _ProxyBulkSetProtocol | None = None, info: _InfoType | None = None, cascade_scalar_deletes: bool = False, create_on_none_assignment: bool = False, init: _NoArg | bool = _NoArg.NO_ARG, repr: _NoArg | bool = _NoArg.NO_ARG, default: Any | None = _NoArg.NO_ARG, default_factory: _NoArg | Callable[[], _T] = _NoArg.NO_ARG, compare: _NoArg | bool = _NoArg.NO_ARG, kw_only: _NoArg | bool = _NoArg.NO_ARG) → AssociationProxy[Any]

返回一个实现对目标属性的视图的 Python 属性,该属性引用目标的成员上的属性。

返回的值是一个AssociationProxy的实例。

实现一个 Python 属性,表示关系作为一组更简单的值,或标量值。代理属性将模仿目标的集合类型(list、dict 或 set),或者在一对一关系的情况下,一个简单的标量值。

参数:

  • target_collection – 立即目标的属性名称。该属性通常由relationship()映射,链接到一个目标集合,但也可以是多对一或非标量关系。
  • attr – 目标实例或实例上可用的关联实例上的属性。
  • creator
    可选。
    定义添加新项到代理集合时的自定义行为。
    默认情况下,向集合添加新项将触发构造目标对象的实例,将给定的项作为位置参数传递给目标构造函数。对于这些情况不足的情况,association_proxy.creator可以提供一个可调用的函数,该函数将以适当的方式构造对象,给定传递的项。
    对于列表和集合导向的集合,将一个参数传递给可调用对象。对于字典导向的集合,将传递两个参数,对应键和值。
    association_proxy.creator可调用对象也用于标量(即多对一,一对一)关系。如果目标关系属性的当前值为None,则使用可调用对象构造一个新对象。如果对象值已存在,则给定的属性值将填充到该对象上。
    另请参阅
    创建新值
  • cascade_scalar_deletes
    当为 True 时,表示将代理值设置为None,或通过del删除时,也应删除源对象。仅适用于标量属性。通常,删除代理目标不会删除代理源,因为该对象可能还有其他状态需要保留。
    新版本 1.3 中引入。
    另请参阅
    级联标量删除 - 完整的使用示例
  • create_on_none_assignment
    当为 True 时,表示将代理值设置为None时应创建源对象(如果不存在),使用创建者。仅适用于标量属性。这与assocation_proxy.cascade_scalar_deletes互斥��
    新版本 2.0.18 中引入。
  • init
    特定于声明性数据类映射,指定映射属性是否应作为由数据类过程生成的__init__()方法的一部分。
    新版本 2.0.0b4 中引入。
  • repr
    特定于声明性数据类映射,指定由此AssociationProxy建立的属性是否应作为由数据类过程生成的__repr__()方法的一部分。
    新版本 2.0.0b4 中引入。
  • default_factory
    特定于声明性数据类映射,指定一个默认值生成函数,该函数将作为由数据类过程生成的__init__()方法的一部分进行。
    新版本 2.0.0b4 中引入。
  • compare
    特定于声明性数据类映射,指示在为映射类生成__eq__()__ne__()方法时,是否应包含此字段进行比较操作。
    新版本 2.0.0b4 中引入。
  • kw_only
    特定于声明性数据类映射,指示在为映射类生成__init__()方法时,是否应将此字段标记为仅关键字参数。
    新版本 2.0.0b4 中引入。
  • info – 可选,如果存在将分配给AssociationProxy.info

以下附加参数涉及在AssociationProxy对象中注入自定义行为,仅供高级使用:

参数:

  • getset_factory
    可选。代理属性访问由根据此代理的 attr 参数获取和设置值的例程自动处理。
    如果您想要自定义此行为,可以提供一个 getset_factory 可调用对象,用于生成 getter 和 setter 函数的元组。工厂函数接受两个参数,即基础集合的抽象类型和此代理实例。
  • proxy_factory – 可选。要模拟的集合类型是通过嗅探目标集合确定的。如果您的集合类型无法通过鸭子类型确定,或者您想使用不同的集合实现,可以提供一个工厂函数来生成这些集合。仅适用于非标量关系。
  • proxy_bulk_set – 可选,与 proxy_factory 一起使用。
class sqlalchemy.ext.associationproxy.AssociationProxy

一个呈现对象属性的读/写视图的描述符。

成员

init(), cascade_scalar_deletes,  create_on_none_assignment, creator, extension_type, for_class(),  getset_factory, info, is_aliased_class, is_attribute, is_bundle,  is_clause_element, is_instance, is_mapper, is_property, is_selectable,  key, proxy_bulk_set, proxy_factory, target_collection, value_attr

类签名

sqlalchemy.ext.associationproxy.AssociationProxy (sqlalchemy.orm.base.InspectionAttrInfo, sqlalchemy.orm.base.ORMDescriptor, sqlalchemy.orm._DCAttributeOptions, sqlalchemy.ext.associationproxy._AssociationProxyProtocol)

method __init__(target_collection: str, attr: str, *, creator: _CreatorProtocol | None = None, getset_factory: _GetSetFactoryProtocol | None = None, proxy_factory: _ProxyFactoryProtocol | None = None, proxy_bulk_set: _ProxyBulkSetProtocol | None = None, info: _InfoType | None = None, cascade_scalar_deletes: bool = False, create_on_none_assignment: bool = False, attribute_options: _AttributeOptions | None = None)

构造一个新的 AssociationProxy

AssociationProxy 对象通常使用 association_proxy() 构造函数来构建。查看 association_proxy() 的描述以获取所有参数的描述。

attribute cascade_scalar_deletes: bool
attribute create_on_none_assignment: bool
attribute creator: _CreatorProtocol | None
attribute extension_type: InspectionAttrExtensionType = 'ASSOCIATION_PROXY'

扩展类型,如果有的话。默认为NotExtension.NOT_EXTENSION

另请参阅

HybridExtensionType

AssociationProxyExtensionType

method for_class(class_: Type[Any], obj: object | None = None) → AssociationProxyInstance[_T]

返回特定于特定映射类的内部状态。

例如,给定一个类User:

class User(Base):
    # ...
    keywords = association_proxy('kws', 'keyword')

如果我们从Mapper.all_orm_descriptors中访问此AssociationProxy,并且我们希望查看由User映射的此代理的目标类:

inspect(User).all_orm_descriptors["keywords"].for_class(User).target_class

返回一个特定于User类的AssociationProxyInstance实例。AssociationProxy对象保持不对其父类进行操作。

参数:

  • class_ – 我们正在返回其状态的类。
  • obj – 可选,如果属性引用多态目标,则需要类的实例,例如,我们必须查看实际目标对象的类型以获取完整路径。

从版本 1.3 开始新增: - AssociationProxy不再存储特定于特定父类的任何状态; 状态现在存储在每个类的AssociationProxyInstance对象中。

attribute getset_factory: _GetSetFactoryProtocol | None
attribute info

继承自 InspectionAttrInfo InspectionAttrInfo.info 属性

与对象相关联的信息字典,允许将用户定义的数据与此InspectionAttr相关联。

字典在首次访问时生成。或者,它可以作为column_property()relationship()composite()函数的构造函数参数指定。

另请参阅

QueryableAttribute.info

SchemaItem.info

attribute is_aliased_class = False

继承自 InspectionAttr InspectionAttr.is_aliased_class 属性

如果此对象是 AliasedClass 的实例,则为真。

attribute is_attribute = True

如果此对象是 Python 描述符,则为真。

此处可能指的是许多类型之一。通常是一个 QueryableAttribute,它代表 MapperProperty 处理属性事件。但也可以是扩展类型,例如 AssociationProxyhybrid_propertyInspectionAttr.extension_type 将引用一个常量,用于标识特定的子类型。

另请参阅

Mapper.all_orm_descriptors

attribute is_bundle = False

继承自 InspectionAttr InspectionAttr.is_bundle 属性

如果此对象是 Bundle 的实例,则为真。

attribute is_clause_element = False

继承自 InspectionAttr InspectionAttr.is_clause_element 属性

如果此对象是 ClauseElement 的实例,则为真。

attribute is_instance = False

继承自 InspectionAttr InspectionAttr.is_instance 属性

如果此对象是 InstanceState 的实例,则为真。

attribute is_mapper = False

继承自 InspectionAttr InspectionAttr.is_mapper 属性

如果此对象是 Mapper 的实例,则为真。

attribute is_property = False

继承自 InspectionAttr InspectionAttr.is_property 属性

如果此对象是 MapperProperty 的实例,则为真。

attribute is_selectable = False

继承自 InspectionAttr InspectionAttr.is_selectable 属性

如果此对象是Selectable的实例,则返回 True。

attribute key: str
attribute proxy_bulk_set: _ProxyBulkSetProtocol | None
attribute proxy_factory: _ProxyFactoryProtocol | None
attribute target_collection: str
attribute value_attr: str
class sqlalchemy.ext.associationproxy.AssociationProxyInstance

一个每类对象,用于提供类和对象特定的结果。

当以特定类或类实例的术语调用AssociationProxy时,即当它被用作常规 Python 描述符时,就会使用此功能。

当作为普通的 Python 描述符引用AssociationProxy时,AssociationProxyInstance是实际提供信息的对象。在正常情况下,其存在是透明的:

>>> User.keywords.scalar
False

当直接访问AssociationProxy对象时,为了获取到AssociationProxyInstance的显式句柄,请使用AssociationProxy.for_class()方法:

proxy_state = inspect(User).all_orm_descriptors["keywords"].for_class(User)
# view if proxy object is scalar or not
>>> proxy_state.scalar
False

在 1.3 版中新增。

成员

eq(), le(), lt(), ne(),  all_(), any(), any_(), asc(), attr, between(), bitwise_and(),  bitwise_lshift(), bitwise_not(), bitwise_or(), bitwise_rshift(),  bitwise_xor(), bool_op(), collate(), collection_class, concat(),  contains(), delete(), desc(), distinct(), endswith(), for_proxy(),  get(), has(), icontains(), iendswith(), ilike(), in_(), info, is_(),  is_distinct_from(), is_not(), is_not_distinct_from(), isnot(),  isnot_distinct_from(), istartswith(), like(), local_attr, match(),  not_ilike(), not_in(), not_like(), notilike(), notin_(), notlike(),  nulls_first(), nulls_last(), nullsfirst(), nullslast(), op(), operate(),  parent, regexp_match(), regexp_replace(), remote_attr,  reverse_operate(), scalar, set(), startswith(), target_class, timetuple

类签名

sqlalchemy.ext.associationproxy.AssociationProxyInstance (sqlalchemy.orm.base.SQLORMOperations)

method __eq__(other: Any) → ColumnOperators

继承自 ColumnOperators sqlalchemy.sql.expression.ColumnOperators.__eq__ *方法。

实现==运算符。

在列上下文中,生成子句a = b。如果目标是None,则生成a IS NULL

method __le__(other: Any) → ColumnOperators

继承自 ColumnOperators sqlalchemy.sql.expression.ColumnOperators.__le__ *方法。

实现<=运算符。

在列上下文中,生成子句a <= b

method __lt__(other: Any) → ColumnOperators

继承自 ColumnOperators sqlalchemy.sql.expression.ColumnOperators.__lt__ *方法。

实现<运算符。

在列上下文中,生成子句a < b

method __ne__(other: Any) → ColumnOperators

继承自 ColumnOperators sqlalchemy.sql.expression.ColumnOperators.__ne__ *方法。

实现!=运算符。

在列上下文中,生成子句a != b。如果目标是None,则生成a IS NOT NULL

method all_() → ColumnOperators

继承自 ColumnOperators ColumnOperators.all_() *方法。

对父对象生成一个all_()子句。

请查看all_()的文档以获取示例。

注意

请确保不要混淆较新的ColumnOperators.all_()方法与此方法的传统版本,即特定于ARRAYComparator.all()方法,其使用不同的调用风格。

method any(criterion: _ColumnExpressionArgument[bool] | None = None, **kwargs: Any) → ColumnElement[bool]

使用 EXISTS 生成一个代理的‘any’表达式。

此表达式将使用基础代理属性的Comparator.any()和/或Comparator.has()运算符进行组合。

method any_() → ColumnOperators

继承自 ColumnOperators.any_() 方法的 ColumnOperators

生成针对父对象的any_()子句。

请参阅any_()文档中的示例。

注意

请务必不要混淆较新的ColumnOperators.any_()方法与旧版该方法,即特定于ARRAYComparator.any()方法,后者使用了不同的调用风格。

method asc() → ColumnOperators

继承自 ColumnOperators.asc() 方法的 ColumnOperators

生成针对父对象的asc()子句。

attribute attr

返回一个元组(local_attr, remote_attr)

该属性最初旨在促进使用Query.join()方法一次加入两个关系,但这使用了一个已弃用的调用风格。

要使用select.join()Query.join()与关联代理,请当前方法是分别使用AssociationProxyInstance.local_attrAssociationProxyInstance.remote_attr属性:

stmt = (
    select(Parent).
    join(Parent.proxied.local_attr).
    join(Parent.proxied.remote_attr)
)

未来版本可能会为关联代理属性提供更简洁的连接模式。

参见

AssociationProxyInstance.local_attr

AssociationProxyInstance.remote_attr

method between(cleft: Any, cright: Any, symmetric: bool = False) → ColumnOperators

继承自 ColumnOperators.between() 方法的 ColumnOperators

对父对象执行between()子句,给定下限和上限范围。

method bitwise_and(other: Any) → ColumnOperators

继承自 ColumnOperators.bitwise_and() 方法的 ColumnOperators

进行按位与操作,通常通过&运算符实现。

版本 2.0.2 中新增。

另请参阅

按位运算符

method bitwise_lshift(other: Any) → ColumnOperators

继承自 ColumnOperators.bitwise_lshift() 方法的 ColumnOperators

进行按位左移操作,通常通过<<运算符实现。

版本 2.0.2 中新增。

另请参阅

按位运算符

method bitwise_not() → ColumnOperators

继承自 ColumnOperators.bitwise_not() 方法的 ColumnOperators

进行按位非操作,通常通过~运算符实现。

版本 2.0.2 中新增。

另请参阅

按位运算符

method bitwise_or(other: Any) → ColumnOperators

继承自 ColumnOperators.bitwise_or() 方法的 ColumnOperators

进行按位或操作,通常通过|运算符实现。

版本 2.0.2 中新增。

另请参阅

按位运算符

method bitwise_rshift(other: Any) → ColumnOperators

继承自 ColumnOperators.bitwise_rshift() 方法的 ColumnOperators

进行按位右移操作,通常通过>>运算符实现。

版本 2.0.2 中新增。

另请参阅

按位运算符

method bitwise_xor(other: Any) → ColumnOperators

继承自 ColumnOperators.bitwise_xor() 方法的 ColumnOperators

执行按位异或操作,通常通过^运算符,或在 PostgreSQL 中使用#

版本 2.0.2 中的新功能。

另请参阅

按位运算符

method bool_op(opstring: str, precedence: int = 0, python_impl: Callable[[...], Any] | None = None) → Callable[[Any], Operators]

继承自 Operators.bool_op() 方法的 Operators

返回自定义布尔运算符。

此方法是调用Operators.op()并传递带有 True 的Operators.op.is_comparison标志的简写。 使用Operators.bool_op()的一个关键优势是,在使用列构造时,返回表达式的“布尔”性质将出现在PEP 484的目的中。

另请参阅

Operators.op()

method collate(collation: str) → ColumnOperators

继承自 ColumnOperators.collate() 方法的 ColumnOperators

生成针对父对象的collate()子句,给定排序字符串。

另请参阅

collate()

attribute collection_class: Type[Any] | None
method concat(other: Any) → ColumnOperators

继承自 ColumnOperators.concat() 方法的 ColumnOperators

实现‘concat’运算符。

在列上下文中,生成子句a || b,或在 MySQL 上使用concat()运算符。

method contains(other: Any, **kw: Any) → ColumnOperators

ColumnOperators.contains() 方法继承而来 ColumnOperators

实现“包含”操作符。

生成一个对字符串值中间进行匹配的 LIKE 表达式:

column LIKE '%' || <other> || '%'

例如:

stmt = select(sometable).\
    where(sometable.c.column.contains("foobar"))

由于该操作符使用LIKE,因此存在于表达式中的通配符字符"%""_"也将像通配符一样工作。对于字面字符串值,可以将ColumnOperators.contains.autoescape标志设置为True,以将这些字符的出现进行转义,使它们匹配为自己而不是通配符字符。或者,ColumnOperators.contains.escape参数将确定给定字符作为转义字符,这在目标表达式不是字面字符串时很有用。

参数:

  • other – 要进行比较的表达式。这通常是一个普通的字符串值,但也可以是任意的 SQL 表达式。除非将ColumnOperators.contains.autoescape标志设置为 True,否则不会转义 LIKE 通配符字符%_
  • autoescape
    布尔值;当为 True 时,在 LIKE 表达式中建立一个转义字符,然后将其应用于比较值内的所有"%""_"和转义字符本身的出现,假定比较值为字面字符串而不是 SQL 表达式。
    例如表达式:
somecolumn.contains("foo%bar", autoescape=True)
  • 将呈现为:
somecolumn LIKE '%' || :param || '%' ESCAPE '/'
  • 其中:param的值为"foo/%bar"
  • escape
    一个字符,当给定时,将使用ESCAPE关键字将其作为转义字符。然后可以将此字符放在%_的前面,以使它们像自己一样工作,而不是通配符字符。
    例如表达式:
somecolumn.contains("foo/%bar", escape="^")
  • 将呈现为:
somecolumn LIKE '%' || :param || '%' ESCAPE '^'
  • 参数也可以与ColumnOperators.contains.autoescape结合使用:
somecolumn.contains("foo%bar^bat", escape="^", autoescape=True)
  • 在上面的示例中,给定的字面参数将在传递到数据库之前转换为"foo^%bar^^bat"

参见

ColumnOperators.startswith()

ColumnOperators.endswith()

ColumnOperators.like()

method delete(obj: Any) → None
method desc() → ColumnOperators

ColumnOperators.desc() 方法继承 ColumnOperators

对父对象产生一个desc()子句。

method distinct() → ColumnOperators

ColumnOperators.distinct() 方法继承 ColumnOperators

对父对象产生一个distinct()子句。

method endswith(other: Any, escape: str | None = None, autoescape: bool = False) → ColumnOperators

ColumnOperators.endswith() 方法继承 ColumnOperators

实现‘endswith’操作符。

生成一个对字符串值末尾进行匹配的 LIKE 表达式:

column LIKE '%' || <other>

例如:

stmt = select(sometable).\
    where(sometable.c.column.endswith("foobar"))

由于操作符使用了LIKE,存在于表达式中的通配符字符"%""_"也将像通配符一样起作用。对于文字字符串值,ColumnOperators.endswith.autoescape标志可以设置为True,以对字符串值中这些字符的出现进行转义,使它们作为自身而不是通配符字符进行匹配。或者,ColumnOperators.endswith.escape参数将建立一个给定的字符作为转义字符,当目标表达式不是文字字符串时可能会有用。

参数:

  • other – 要比较的表达式。这通常是一个普通的字符串值,但也可以是任意的 SQL 表达式。除非将ColumnOperators.endswith.autoescape标志设置为 True,否则不会默认转义 LIKE 通配符%_
  • autoescape
    布尔值;当为 True 时,在 LIKE 表达式中建立一个转义字符,然后将其应用于比较值中所有的"%""_"以及转义字符本身的出现,假定比较值是一个文字字符串而不是 SQL 表达式。
    一个表达式如下:
somecolumn.endswith("foo%bar", autoescape=True)
  • 将被渲染为:
somecolumn LIKE '%' || :param ESCAPE '/'
  • 其中:param的值为"foo/%bar"
  • escape
    一个字符,当给定时将会使用ESCAPE关键字来确定该字符作为转义字符。然后可以将此字符放在%_的前面,以允许它们作为自身而不是通配符字符。
    一个表达式如下:
somecolumn.endswith("foo/%bar", escape="^")
  • 将被渲染为:
somecolumn LIKE '%' || :param ESCAPE '^'
  • 此参数还可以与ColumnOperators.endswith.autoescape结合使用:
somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)
  • 给定的文字参数在传递到数据库之前将被转换为"foo^%bar^^bat"

另请参阅

ColumnOperators.startswith()

ColumnOperators.contains()

ColumnOperators.like()

classmethod for_proxy(parent: AssociationProxy[_T], owning_class: Type[Any], parent_instance: Any) → AssociationProxyInstance[_T]
method get(obj: Any) → _T | None | AssociationProxyInstance[_T]
method has(criterion: _ColumnExpressionArgument[bool] | None = None, **kwargs: Any) → ColumnElement[bool]

使用 EXISTS 生成一个代理的‘has’表达式。

此表达式将使用底层代理属性的Comparator.any()和/或Comparator.has()运算符的组合产品。

method icontains(other: Any, **kw: Any) → ColumnOperators

继承自 ColumnOperators.icontains() 方法的 ColumnOperators

实现icontains运算符,例如ColumnOperators.contains()的不区分大小写版本。

生成一个对字符串值中间进行大小写不敏感匹配的 LIKE 表达式:

lower(column) LIKE '%' || lower(<other>) || '%'

例如:

stmt = select(sometable).\
    where(sometable.c.column.icontains("foobar"))

由于操作符使用了 LIKE,存在于表达式中的通配符字符 "%""_" 也会像通配符一样行为。对于字面字符串值,可以将ColumnOperators.icontains.autoescape标志设置为 True,以将这些字符在字符串值中的出现转义,使它们与自身匹配而不是通配符字符。或者,ColumnOperators.icontains.escape参数将建立一个给定字符作为转义字符,当目标表达式不是字面字符串时,这可能会有用。

参数:

  • other – 待比较的表达式。通常这是一个简单的字符串值,但也可以是任意的 SQL 表达式。除非设置了ColumnOperators.icontains.autoescape标志为 True,否则 LIKE 通配符字符 %_ 不会被转义。
  • autoescape
    布尔值;当为 True 时,在 LIKE 表达式中建立一个转义字符,然后将其应用于比较值中的所有出现的 "%""_" 和转义字符本身,假定比较值是一个字面字符串而不是 SQL 表达式。
    一个表达式,比如:
somecolumn.icontains("foo%bar", autoescape=True)
  • 将呈现为:
lower(somecolumn) LIKE '%' || lower(:param) || '%' ESCAPE '/'
  • 具有值 :param"foo/%bar"
  • escape
    一个字符,当给定时,将使用 ESCAPE 关键字将该字符建立为转义字符。然后,该字符可以放在 %_ 的前面,以允许它们以自身形式而不是通配符字符的形式进行操作。
    一个表达式,比如:
somecolumn.icontains("foo/%bar", escape="^")
  • 将呈现为:
lower(somecolumn) LIKE '%' || lower(:param) || '%' ESCAPE '^'
  • 参数也可以与ColumnOperators.contains.autoescape结合使用:
somecolumn.icontains("foo%bar^bat", escape="^", autoescape=True)
  • 在上述情况下,给定的字面参数将在传递到数据库之前转换为 "foo^%bar^^bat"

另请参阅

ColumnOperators.contains()

method iendswith(other: Any, escape: str | None = None, autoescape: bool = False) → ColumnOperators

继承自 ColumnOperators.iendswith() 方法的 ColumnOperators

实现iendswith操作符,例如,ColumnOperators.endswith()的不区分大小写版本。

生成一个 LIKE 表达式,用于对字符串值的结尾进行不区分大小写匹配:

lower(column) LIKE '%' || lower(<other>)

例如:

stmt = select(sometable).\
    where(sometable.c.column.iendswith("foobar"))

由于该操作符使用LIKE,在表达式中存在的通配符字符"%""_"也将像通配符一样起作用。对于文字字符串值,可以将ColumnOperators.iendswith.autoescape标志设置为True,以对字符串值中这些字符的出现进行转义,使它们匹配为它们自身而不是通配符字符。或者,ColumnOperators.iendswith.escape参数将建立一个给定字符作为转义字符,当目标表达式不是文字字符串时可能会有用。

参数:

  • other – 要进行比较的表达式。这通常是一个简单的字符串值,但也可以是任意的 SQL 表达式。默认情况下,LIKE 通配符字符%_不会被转义,除非将ColumnOperators.iendswith.autoescape标志设置为 True。
  • autoescape
    布尔值;当为 True 时,在 LIKE 表达式中建立一个转义字符,然后将其应用于比较值中所有的"%""_"和转义字符本身的出现,假定比较值是一个文字字符串而不是 SQL 表达式。
    一个表达式,例如:
somecolumn.iendswith("foo%bar", autoescape=True)
  • 将呈现为:
lower(somecolumn) LIKE '%' || lower(:param) ESCAPE '/'
  • 其中:param的值为"foo/%bar"
  • escape
    一个字符,当给定时,将呈现为ESCAPE关键字,以将该字符建立为转义字符。然后可以将此字符放在%_的前面,以允许它们作为自身而不是通配符字符。
    一个表达式,例如:
somecolumn.iendswith("foo/%bar", escape="^")
  • 将呈现为:
lower(somecolumn) LIKE '%' || lower(:param) ESCAPE '^'
  • 该参数也可以与ColumnOperators.iendswith.autoescape结合使用:
somecolumn.endswith("foo%bar^bat", escape="^", autoescape=True)
  • 在上述情况下,给定的文字参数将在传递到数据库之前转换为"foo^%bar^^bat"

另请参阅

ColumnOperators.endswith()

method ilike(other: Any, escape: str | None = None) → ColumnOperators

继承自 ColumnOperators.ilike() 方法的 ColumnOperators

实现ilike运算符,例如,不区分大小写的 LIKE。

在列上下文中,产生一个形式为:

lower(a) LIKE lower(other)

或者在支持 ILIKE 运算符的后端上:

a ILIKE other

例如:

stmt = select(sometable).\
    where(sometable.c.column.ilike("%foobar%"))

参数:

  • other – 要比较的表达式
  • escape
    可选的转义字符,呈现ESCAPE关键字,例如:
somecolumn.ilike("foo/%bar", escape="/")

另请参阅

ColumnOperators.like()

method in_(other: Any) → ColumnOperators

继承自 ColumnOperators.in_() 方法的 ColumnOperators

实现in运算符。

在列上下文中,产生子句column IN

给定的参数other可以是:

  • 一个字面值列表,例如:
stmt.where(column.in_([1, 2, 3]))
  • 在这种调用形式中,项目列表被转换为与给定列表长度相同的一组绑定参数:
WHERE COL IN (?, ?, ?)
  • 如果比较是针对包含多个表达式的tuple_()的元组,则可以提供一个元组列表:
from sqlalchemy import tuple_
stmt.where(tuple_(col1, col2).in_([(1, 10), (2, 20), (3, 30)]))
  • 一个空列表,例如:
stmt.where(column.in_([]))
  • 在这种调用形式中,表达式呈现出一个“空集”表达式。这些表达式是针对各个后端进行定制的,通常试图将一个空的 SELECT 语句作为子查询。例如,在 SQLite 上,表达式是:
WHERE col IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)
  • 从版本 1.4 开始:所有情况下空的 IN 表达式现在使用执行时生成的 SELECT 子查询。
  • 如果包含bindparam(),则可以使用绑定参数,例如包含bindparam.expanding标志:
stmt.where(column.in_(bindparam('value', expanding=True)))
  • 在这种调用形式中,表达式呈现出一个特殊的非 SQL 占位符表达式,看起来像:
WHERE COL IN ([EXPANDING_value])
  • 此占位符表达式在语句执行时被拦截,转换为前面所示的可变数量的绑定参数形式。如果语句执行为:
connection.execute(stmt, {"value": [1, 2, 3]})
  • 数据库将为每个值传递一个绑定参数:
WHERE COL IN (?, ?, ?)
  • 版本 1.2 中新增:添加了“expanding”绑定参数
    如果传递一个空列表,则呈现一个特殊的“空列表”表达式,这是特定于正在使用的数据库的。在 SQLite 上,这将是:
WHERE COL IN (SELECT 1 FROM (SELECT 1) WHERE 1!=1)
  • 版本 1.3 中新增��现在“expanding”绑定参数支持空列表
  • 一个select()构造,通常是一个相关的标量选择:
stmt.where(
    column.in_(
        select(othertable.c.y).
        where(table.c.x == othertable.c.x)
    )
)
  • 在这种调用形式中,ColumnOperators.in_()呈现如下:
WHERE COL IN (SELECT othertable.y
FROM othertable WHERE othertable.x = table.x)


SqlAlchemy 2.0 中文文档(二十九)(2)https://developer.aliyun.com/article/1560465

相关文章
|
2天前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(二十九)(3)
SqlAlchemy 2.0 中文文档(二十九)
16 4
|
2天前
|
SQL 数据库 Python
SqlAlchemy 2.0 中文文档(二十六)(4)
SqlAlchemy 2.0 中文文档(二十六)
13 2
|
2天前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(二十九)(2)
SqlAlchemy 2.0 中文文档(二十九)
20 7
|
2天前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(二十九)(4)
SqlAlchemy 2.0 中文文档(二十九)
15 4
|
2天前
|
SQL 前端开发 关系型数据库
SqlAlchemy 2.0 中文文档(二十七)(2)
SqlAlchemy 2.0 中文文档(二十七)
14 2
|
2天前
|
SQL 缓存 前端开发
SqlAlchemy 2.0 中文文档(二十七)(5)
SqlAlchemy 2.0 中文文档(二十七)
10 2
|
2天前
|
自然语言处理 数据库 Python
SqlAlchemy 2.0 中文文档(二十六)(2)
SqlAlchemy 2.0 中文文档(二十六)
12 2
|
2天前
|
SQL 缓存 数据库连接
SqlAlchemy 2.0 中文文档(二十六)(1)
SqlAlchemy 2.0 中文文档(二十六)
12 2
|
2天前
|
SQL 缓存 数据库连接
SqlAlchemy 2.0 中文文档(二十六)(3)
SqlAlchemy 2.0 中文文档(二十六)
11 2
|
2天前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(二十九)(5)
SqlAlchemy 2.0 中文文档(二十九)
11 1