列集可以与单个用户定义的数据类型相关联。ORM提供了一个单独的属性,该属性表示使用您提供的类的列组。
一个简单的示例将列对表示为 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/y1
和 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_registry.map_imperatively(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),
})
我们现在可以坚持和使用 Vertex
实例以及对它们的查询,使用 .start
和 .end
特殊属性 Point
实例:
>>> 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)
BEGIN (implicit)
INSERT INTO vertices (x1, y1, x2, y2) VALUES (?, ?, ?, ?)
(3, 4, 5, 6)
SELECT vertices.id AS vertices_id,
vertices.x1 AS vertices_x1,
vertices.y1 AS vertices_y1,
vertices.x2 AS vertices_x2,
vertices.y2 AS vertices_y2
FROM vertices
WHERE vertices.x1 = ? AND vertices.y1 = ?
LIMIT ? OFFSET ?
(3, 4, 1, 0)
Point(x=3, y=4)
Object Name | Description |
---|---|
composite(class_, *attrs, **kwargs) |
返回用于映射器的基于复合列的属性。 |
返回用于映射器的基于复合列的属性。
请参见“映射文档”部分 组合列类型 完整用法示例。
这个 MapperProperty
返回的 composite()
是 CompositeProperty
.
class_¶ -- “composite type”类,或任何classmethod或callable,它将在给定列值的情况下生成复合对象的新实例。
*cols¶ -- 要映射的列对象列表。
active_history=False¶ -- 什么时候? True
指示如果尚未加载,则在替换时应加载标量属性的“上一个”值。在上看到相同的标志 column_property()
.
group¶ -- 当标记为延迟时,此属性的组名。
deferred¶ -- 如果为true,则列属性为“deferred”,这意味着它不会立即加载,而是在实例上首次访问属性时加载。也见 deferred()
.
comparator_factory¶ -- 扩展的类 Comparator
它为比较操作提供自定义SQL子句生成。
doc¶ -- 将作为类绑定描述符上的文档应用的可选字符串。
info¶ -- 可选数据字典,将填充到 MapperProperty.info
此对象的属性。
对现有组合值的就地更改不会自动跟踪。相反,复合类需要显式地向其父对象提供事件。通过使用 MutableComposite
mixin,它使用事件将每个用户定义的复合对象与所有父关联关联起来。请参阅中的示例 确定复合材料的易变性 .
默认情况下,“等于”比较操作会生成一个和,其中所有相应的列彼此相等。可以使用 comparator_factory
参数 composite()
,其中我们指定了一个自定义 Comparator
类来定义现有或新操作。下面我们演示“大于”运算符,实现与基“大于”相同的表达式:
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)
复合对象可以定义为在简单的嵌套方案中工作,方法是将复合类中的行为重新定义为根据需要工作,然后通常将复合类映射到单个列的完整长度。通常,可以方便地为用户定义的使用定义单独的构造函数,并从行使用中生成。下面我们重组 Vertex
类自身是复合对象,然后将其映射到类 HasVertex
::
from sqlalchemy.orm import composite
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)
class Vertex(object):
def __init__(self, start, end):
self.start = start
self.end = end
@classmethod
def _generate(self, x1, y1, x2, y2):
"""generate a Vertex from a row"""
return Vertex(
Point(x1, y1),
Point(x2, y2)
)
def __composite_values__(self):
return \
self.start.__composite_values__() + \
self.end.__composite_values__()
class HasVertex(Base):
__tablename__ = 'has_vertex'
id = Column(Integer, primary_key=True)
x1 = Column(Integer)
y1 = Column(Integer)
x2 = Column(Integer)
y2 = Column(Integer)
vertex = composite(Vertex._generate, x1, y1, x2, y2)
然后我们可以使用上面的映射作为:
hv = HasVertex(vertex=Vertex(Point(1, 2), Point(3, 4)))
s.add(hv)
s.commit()
hv = s.query(HasVertex).filter(
HasVertex.vertex == Vertex(Point(1, 2), Point(3, 4))).first()
print(hv.vertex.start)
print(hv.vertex.end)
flambé! the dragon and The Alchemist image designs created and generously donated by Rotem Yaari.
Created using Sphinx 4.2.0.