可索引


在 ORM 映射类上定义属性,这些类具有具有 Indexable 类型的列的 “index” 属性。


“index” 表示该属性与 indexable 列,其中包含预定义的索引以访问它。可索引类型包括 ARRAY、JSONHSTORE 的。


可索引扩展提供 状接口,用于 可索引类型化列。在简单情况下,可以将其视为 Column - mapped 属性。


剧情简介


给定 Person 作为具有主键和 JSON 数据字段的模型。虽然这个字段可能编码了任意数量的元素,但我们希望将名为 name 的元素单独称为专用属性,其行为类似于独立列:

from sqlalchemy import Column, JSON, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.indexable import index_property

Base = declarative_base()


class Person(Base):
    __tablename__ = "person"

    id = Column(Integer, primary_key=True)
    data = Column(JSON)

    name = index_property("data", "name")


在上面,name 属性现在的行为类似于映射列。我们可以编写一个新的 Person 并设置 name 的值:

>>> person = Person(name="Alchemist")


该值现在可以访问:

>>> person.name
'Alchemist'


在后台,JSON 字段被初始化为一个新的空白字典,并设置了该字段:

>>> person.data
{'name': 'Alchemist'}


该字段就地可变:

>>> person.name = "Renamed"
>>> person.name
'Renamed'
>>> person.data
{'name': 'Renamed'}


使用 index_property 时,我们对可索引结构所做的更改也会自动作为历史记录进行跟踪;我们不再需要使用 MutableDict 来跟踪工作单元的此更改。


删除作也正常进行:

>>> del person.name
>>> person.data
{}


在上面,删除 person.name 会从字典中删除值,但不会删除字典本身。


缺少 key 将产生 AttributeError

>>> person = Person()
>>> person.name
AttributeError: 'name'


除非您设置了默认值:

>>> class Person(Base):
...     __tablename__ = "person"
...
...     id = Column(Integer, primary_key=True)
...     data = Column(JSON)
...
...     name = index_property("data", "name", default=None)  # See default

>>> person = Person()
>>> print(person.name)
None


这些属性也可以在类级别访问。下面,我们说明了用于生成索引 SQL 标准的 Person.name

>>> from sqlalchemy.orm import Session
>>> session = Session()
>>> query = session.query(Person).filter(Person.name == "Alchemist")


上述查询等效于:

>>> query = session.query(Person).filter(Person.data["name"] == "Alchemist")


可以链接多个 index_property 对象以生成多个级别的索引:

from sqlalchemy import Column, JSON, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.indexable import index_property

Base = declarative_base()


class Person(Base):
    __tablename__ = "person"

    id = Column(Integer, primary_key=True)
    data = Column(JSON)

    birthday = index_property("data", "birthday")
    year = index_property("birthday", "year")
    month = index_property("birthday", "month")
    day = index_property("birthday", "day")


上面,查询如下:

q = session.query(Person).filter(Person.year == "1980")


在 PostgreSQL 后端,上述查询将呈现为:

SELECT person.id, person.data
FROM person
WHERE person.data -> %(data_1)s -> %(param_1)s = %(param_2)s


默认值


index_property 包括索引数据结构不存在时的特殊行为,并且调用 set作:


  • 对于给定整数索引值的 index_property,默认数据结构将是 None 值的 Python 列表,至少与索引值一样长;然后,该值将设置在列表中的位置。这意味着对于索引值为零,在设置给定值之前,列表将初始化为 [None]。 对于 index 值 5,列表将初始化为 [None, None, None, None, None] 在将 Fifth Element 设置为给定值之前。请注意,现有列表不会就地扩展以接收值。


  • 对于给定任何其他类型的索引值(例如通常为字符串)的index_property,Python 字典用作默认数据结构。


  • 默认数据结构可以使用 index_property.datatype 参数,覆盖前面的规则。


子类化¶


index_property可以子类化,特别是对于在访问值或 SQL 表达式时提供值或 SQL 表达式强制的常见用例。以下是用于 PostgreSQL JSON 类型的常见配方,其中我们还希望包括自动转换加 astext():

class pg_json_property(index_property):
    def __init__(self, attr_name, index, cast_type):
        super(pg_json_property, self).__init__(attr_name, index)
        self.cast_type = cast_type

    def expr(self, model):
        expr = super(pg_json_property, self).expr(model)
        return expr.astext.cast(self.cast_type)


上述子类可以与 PostgreSQL 特定的 JSON 版本一起使用:

from sqlalchemy import Column, Integer
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.dialects.postgresql import JSON

Base = declarative_base()


class Person(Base):
    __tablename__ = "person"

    id = Column(Integer, primary_key=True)
    data = Column(JSON)

    age = pg_json_property("data", "age", Integer)


实例级别的 age 属性的工作方式与以前一样;但是,在呈现 SQL 时,PostgreSQL 的 ->> 运算符将用于索引访问,而不是通常的 -> 索引运算符:

>>> query = session.query(Person).filter(Person.age < 20)


上述查询将呈现:..源代码:: SQL


SELECT person.id, person.data FROM person WHERE CAST(person.data ->> %(data_1)s AS INTEGER) < %(param_1)s


API 参考


对象名称

描述

index_property


属性生成器。generated 属性描述对应于 Indexable 的对象属性 列。


sqlalchemy.ext.indexable 中。index_property


属性生成器。generated 属性描述对应于 Indexable 的对象属性 列。


方法 sqlalchemy.ext.indexable.index_property. __init__attr_nameindexdefault=<object object>datatype=Nonemutable=Trueonebased=True


创建新index_property


参数

  • attr_name可索引类型列的属性名称,或返回可索引结构的其他属性。


  • index- 用于获取和设置此值的索引。这应该是整数的 Python 端索引值。


  • default – 将返回的值,而不是 AttributeError 当给定索引处没有值时。


  • datatype- 字段为空时使用的默认数据类型。 默认情况下,这是从使用的索引类型派生的;一个 Python list 用于整数索引,或者 Python 字典用于 任何其他样式的索引。 对于列表,列表将为 initialized 为至少为 index elements 长。


  • mutable——如果为 False,则不允许对属性进行写入和删除。


  • onebased —— 假设该值的 SQL 表示形式从 1 开始;也就是说,SQL 中的第一个索引是 1,而不是 0。