Python 在声明式SQLAlchemy中创建容器关系
我的Python/SQLAlchemy应用程序管理一组节点,所有节点都派生自基类节点。我正在使用SQLAlchemy的多态性特性来管理 SQLite3表中的节点。下面是基本节点类的定义: 作为示例,其中一个派生类NoteNode: 现在我需要一种新的节点,ListNode,它是一个由零个或多个节点组成的有序容器。加载ListNode时,我希望它具有ID和标题 (来自基本节点类)及其包含(子)节点的集合。一个节点可能出现在多个ListNode中,因此它不是一个适当的层次结构。我将按照以下思路创建它们:Python 在声明式SQLAlchemy中创建容器关系,python,sqlalchemy,Python,Sqlalchemy,我的Python/SQLAlchemy应用程序管理一组节点,所有节点都派生自基类节点。我正在使用SQLAlchemy的多态性特性来管理 SQLite3表中的节点。下面是基本节点类的定义: 作为示例,其中一个派生类NoteNode: 现在我需要一种新的节点,ListNode,它是一个由零个或多个节点组成的有序容器。加载ListNode时,我希望它具有ID和标题 (来自基本节点类)及其包含(子)节点的集合。一个节点可能出现在多个ListNode中,因此它不是一个适当的层次结构。我将按照以下思路创建它
note1 = NoteNode(title=u"Note 1", content_type="text/text", content=u"I am note #1")
session.add(note1)
note2 = NoteNode(title=u"Note 2", content_type="text/text", content=u"I am note #2")
session.add(note2)
list1 = ListNode(title=u"My List")
list1.items = [note1,note2]
session.add(list1)
儿童名单只应包括
由节点对象组成——也就是说,我只需要它们的基类。他们不应该完全进入专业课程
(因此,除其他原因外,我无法立即获得整个图表)
我沿着下面的路线开始,把我在不同地方发现的零碎东西拼凑在一起,而对这些东西没有完全的了解
发生了什么,所以这可能没有多大意义:
class ListNode(Node):
__mapper_args__ = {'polymorphic_identity': 'list', 'inherit_condition':id==Node.id}
__tablename__ = 'nodes_list_contents'
id = Column(None, ForeignKey('nodes.id'), primary_key=True)
item_id = Column(None, ForeignKey('nodes.id'), primary_key=True)
items = relation(Node, primaryjoin="Node.id==ListNode.item_id")
这种方法在以下几个方面失败:它似乎不允许空的ListNode,并且将items属性设置为list结果
在SQLAlchemy中,抱怨“list”对象没有属性“\u sa\u instance\u state”。毫不奇怪,数小时的随机突变并没有给这个主题带来任何影响
好成绩,
我在SQLAlchemy方面的经验有限,但我真的很想尽快让它发挥作用。如果您能给我任何建议或指导,我将不胜感激
提供提前谢谢 对于多对多关系,您需要一个额外的表:
nodes_list_nodes = Table(
'nodes_list_nodes', metadata,
Column('parent_id', None, ForeignKey('nodes_list.id'), nullable=False),
Column('child_id', None, ForeignKey(Node.id), nullable=False),
PrimaryKeyConstraint('parent_id', 'child_id'),
)
class ListNode(Node):
__mapper_args__ = {'polymorphic_identity': 'list'}
__tablename__ = 'nodes_list'
id = Column(None, ForeignKey('nodes.id'), primary_key=True)
items = relation(Node, secondary=nodes_list_nodes)
更新:下面是使用关联\u代理的有序列表示例:
from sqlalchemy.orm.collections import InstrumentedList
from sqlalchemy.ext.associationproxy import association_proxy
class ListNodeAssociation(Base):
__tablename__ = 'nodes_list_nodes'
parent_id = Column(None, ForeignKey('nodes_list.id'), primary_key=True)
child_id = Column(None, ForeignKey(Node.id), primary_key=True)
order = Column(Integer, nullable=False, default=0)
child = relation(Node)
__table_args__ = (
PrimaryKeyConstraint('parent_id', 'child_id'),
{},
)
class OrderedList(InstrumentedList):
def append(self, item):
if self:
item.order = self[-1].order+1
else:
item.order = 1
InstrumentedList.append(self, item)
class ListNode(Node):
__mapper_args__ = {'polymorphic_identity': 'list'}
__tablename__ = 'nodes_list'
id = Column(None, ForeignKey('nodes.id'), primary_key=True)
_items = relation(ListNodeAssociation,
order_by=ListNodeAssociation.order,
collection_class=OrderedList,
cascade='all, delete-orphan')
items = association_proxy(
'_items', 'child',
creator=lambda item: ListNodeAssociation(child=item))
这将导致“items”是实际Item对象的列表,对吗?二进制关系最终是完全透明的,这样他就不需要associationproxy跳过它到实际对象,对吗?对,这种情况很简单。使用中间模型时需要associationproxy,即使列表有序(连接表中的添加顺序字段)。非常感谢Denis-这真的打破了僵局。如果我可以更进一步,我已经用声明式风格重写了关系表:class ListNodeAssociation(Base):tablename='nodes\u list\u nodes'parent\u id=Column(无,ForeignKey('nodes\u list.id'),primary\u key=True)child\u id=Column(无,ForeignKey(Node.id),primary\u key=True)我仍然需要关系井然有序,最好是通过SQLAlchemy“orderinglist”机制,但我不清楚它在这种情况下是如何应用的。。。它是否适用,如果适用,如何适用?您可以将原始问题正确地更新,并将新代码标记为更新。或者用更好的标题发布另一个问题(指这一个),这样其他人就可以很容易地找到它。
nodes_list_nodes = Table(
'nodes_list_nodes', metadata,
Column('parent_id', None, ForeignKey('nodes_list.id'), nullable=False),
Column('child_id', None, ForeignKey(Node.id), nullable=False),
PrimaryKeyConstraint('parent_id', 'child_id'),
)
class ListNode(Node):
__mapper_args__ = {'polymorphic_identity': 'list'}
__tablename__ = 'nodes_list'
id = Column(None, ForeignKey('nodes.id'), primary_key=True)
items = relation(Node, secondary=nodes_list_nodes)
from sqlalchemy.orm.collections import InstrumentedList
from sqlalchemy.ext.associationproxy import association_proxy
class ListNodeAssociation(Base):
__tablename__ = 'nodes_list_nodes'
parent_id = Column(None, ForeignKey('nodes_list.id'), primary_key=True)
child_id = Column(None, ForeignKey(Node.id), primary_key=True)
order = Column(Integer, nullable=False, default=0)
child = relation(Node)
__table_args__ = (
PrimaryKeyConstraint('parent_id', 'child_id'),
{},
)
class OrderedList(InstrumentedList):
def append(self, item):
if self:
item.order = self[-1].order+1
else:
item.order = 1
InstrumentedList.append(self, item)
class ListNode(Node):
__mapper_args__ = {'polymorphic_identity': 'list'}
__tablename__ = 'nodes_list'
id = Column(None, ForeignKey('nodes.id'), primary_key=True)
_items = relation(ListNodeAssociation,
order_by=ListNodeAssociation.order,
collection_class=OrderedList,
cascade='all, delete-orphan')
items = association_proxy(
'_items', 'child',
creator=lambda item: ListNodeAssociation(child=item))