版本: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__()方法来测试两个实例的相等性。

We will create a mapping to a table vertices, which represents two points as x1/y1 and x2/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时,表示标量属性的“previous”值在替换时应加载,如果尚未加载。查看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)