版本:1.1.0b2 |发布日期:2016年7月1日

SQLAlchemy 1.1文档

复合列类型

一组列可以与单个用户定义的数据类型相关联。ORM提供了一个单一的属性,它表示使用您提供的类的列组。

在版本0.7中更改:复合材料已经过简化,不再“隐藏”基础列的属性。另外,就地突变不再是自动的;请参阅以下关于启用可变性以支持就地更改跟踪的部分。

在版本0.9中更改:在面向列的Query构造中使用时,复合材料将返回它们的对象形式,而不是单个列。请参阅Composite attributes are now returned as their object form when queried on a per-attribute basis查询时,复合属性现在以其对象形式返回。

一个简单的例子表示成对的列作为Point对象。Point表示如.x.y这样的一对:

class Point(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __composite_values__(self):
        return self.x, self.y

    def __repr__(self):
        return "Point(x=%r, y=%r)" % (self.x, self.y)

    def __eq__(self, other):
        return isinstance(other, Point) and \
            other.x == self.x and \
            other.y == self.y

    def __ne__(self, other):
        return not self.__eq__(other)

自定义数据类型类的要求是它有一个构造函数,它接受与其列格式相对应的位置参数,并且还提供了一个方法__composite_values__(),它将对象的状态作为列表或元组返回,按照其基于列的属性。它还应提供足够的__eq__()__ne__()方法来测试两个实例的相等性。

我们将创建一个映射到一个表vertices,它将两个点表示为x1/y1x2/y2这些通常被创建为Column对象。然后,composite()函数用于分配新属性,这些新属性将通过Point类表示一组列。

from sqlalchemy import Column, Integer
from sqlalchemy.orm import composite
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Vertex(Base):
    __tablename__ = 'vertices'

    id = Column(Integer, primary_key=True)
    x1 = Column(Integer)
    y1 = Column(Integer)
    x2 = Column(Integer)
    y2 = Column(Integer)

    start = composite(Point, x1, y1)
    end = composite(Point, x2, y2)

上面的经典映射会根据现有表定义每个composite()

mapper(Vertex, vertices_table, properties={
    'start':composite(Point, vertices_table.c.x1, vertices_table.c.y1),
    'end':composite(Point, vertices_table.c.x2, vertices_table.c.y2),
})

We can now persist and use Vertex instances, as well as query for them, using the .start and .end attributes against ad-hoc Point instances:

>>> v = Vertex(start=Point(3, 4), end=Point(5, 6))
>>> session.add(v)
>>> q = session.query(Vertex).filter(Vertex.start == Point(3, 4))
sql>>> print(q.first().start)
Point(x=3, y=4)
sqlalchemy.orm.composite(class_, *attrs, **kwargs)

返回一个组合的基于列的属性以用于Mapper。

完整的使用示例请参见映射文档部分Composite Column Types

composite()返回的MapperPropertyCompositeProperty

参数:
  • class _ - “复合类型”类。
  • * cols - 要映射的列对象列表。
  • active_history = False -

    True时,表示标量属性的“上一个”值在替换时应加载,如果尚未加载。查看column_property()上的同一个标志。

    版本0.7中更改:此标志特别有意义 - 以前它是占位符。

  • group – A group name for this property when marked as deferred.
  • deferred – When True, the column property is “deferred”, meaning that it does not load immediately, and is instead loaded when the attribute is first accessed on an instance. 另见deferred()
  • comparator_factory – a class which extends CompositeProperty.Comparator which provides custom SQL clause generation for comparison operations.
  • doc – optional string that will be applied as the doc on the class-bound descriptor.
  • info -

    可选数据字典,将填充到此对象的MapperProperty.info属性中。

    0.8版本中的新功能

  • extension – an AttributeExtension instance, or list of extensions, which will be prepended to the list of attribute listeners for the resulting descriptor placed on the class. 已过时。 T0>请参阅AttributeEvents

跟踪复合材料上的原位变异

不会自动跟踪现有组合值的就地更改。相反,复合类需要显式地将事件提供给其父对象。通过使用MutableComposite mixin,该任务在很大程度上是自动化的,它使用事件将每个用户定义的复合对象与所有父关联相关联。请参阅Establishing Mutability on Composites中的示例。

在版本0.7中更改:现有合成值的就地更改不再自动进行跟踪;该功能被MutableComposite类所取代。

重新定义复合材料的比较操作

默认情况下,“等于”比较操作会产生所有对应列的“与”。This can be changed using the comparator_factory argument to composite(), where we specify a custom CompositeProperty.Comparator class to define existing or new operations. 下面我们说明“大于”运算符,实现与“大于”基数相同的表达式:

from sqlalchemy.orm.properties import CompositeProperty
from sqlalchemy import sql

class PointComparator(CompositeProperty.Comparator):
    def __gt__(self, other):
        """redefine the 'greater than' operation"""

        return sql.and_(*[a>b for a, b in
                          zip(self.__clause_element__().clauses,
                              other.__composite_values__())])

class Vertex(Base):
    ___tablename__ = 'vertices'

    id = Column(Integer, primary_key=True)
    x1 = Column(Integer)
    y1 = Column(Integer)
    x2 = Column(Integer)
    y2 = Column(Integer)

    start = composite(Point, x1, y1,
                        comparator_factory=PointComparator)
    end = composite(Point, x2, y2,
                        comparator_factory=PointComparator)