如何解决SQLAlchemy自引用具有关联代理和对象映射表的多对多
我正在尝试在Flask中建立自引用多对多模型。我已经在互联网上检查了很多示例,但就我而言,我想使用对象映射表来处理这种关系。另外,因为我将Flask和棉花糖一起使用,所以我想在表中包括关联代理,以简化模型的序列化。我发现的每个示例都在使用backref
,但出于可读性考虑,我想使用back_populates
进行创建。目前,我不确定是否可行。
请在下面的最小示例中找到该问题的说明。
from sqlalchemy import Table,Column,Integer,String,ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.associationproxy import association_proxy
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///:memory:',echo=True)
Session = sessionmaker(bind=engine)
session = Session()
Base = declarative_base()
class NodeRelation(Base):
__tablename__ = "node_relation"
parent_id = Column(Integer,ForeignKey('node.id'),primary_key=True)
parent = relationship('Node',primaryjoin="NodeRelation.parent_id == node.c.id",back_populates='parent_childs',#foreign_keys=parent_id
)
child_id = Column(Integer,primary_key=True)
child = relationship('Node',primaryjoin="NodeRelation.child_id == node.c.id",back_populates='child_parents',#foreign_keys=child_id
)
def __init__(self,parent=None,child=None,**kwargs):
super().__init__(**kwargs)
if child:
self.child = child
if parent:
self.parent = parent
def __repr__(self):
return "(parent_id: %s,child_id: %s)" % (self.parent_id,self.child_id)
class Node(Base):
__tablename__ = "node"
id = Column(Integer,primary_key=True,autoincrement=True)
title = Column(String())
parent_childs = relationship('NodeRelation',primaryjoin="Node.id==node_relation.c.parent_id",back_populates='parent',cascade='all,delete',#foreign_keys=NodeRelation.parent_id
)
parents = association_proxy('parent_childs','parent',creator=lambda parent: NodeRelation(parent=parent))
child_parents = relationship('NodeRelation',primaryjoin="Node.id==node_relation.c.child_id",back_populates='child',#foreign_keys=NodeRelation.child_id
)
childs = association_proxy('child_parents','child',creator=lambda child: NodeRelation(child=child))
def __init__(self,title,**kwargs):
super().__init__(**kwargs)
self.title = title
def __repr__(self):
return "(id: %s,title: %s,childs: %s)" % (self.id,self.title,self.childs)
Base.metadata.create_all(engine)
n1 = Node("First")
n2 = Node("Second")
"""
# This is failing with: NOT NULL constraint failed: node_relation.parent_id
n1.childs.append(n2)
session.add(n1)
session.add(n2)
session.commit()
"""
# This one is working
c = NodeRelation(n1,n2)
session.add(n1)
session.add(n2)
session.add(c)
# Node 1 and Node 2 exists
q = session.query(NodeRelation).all()
print(q)
# This is failing with infinite recursion when childs property is displayed.
q2 = session.query(Node).all()
print(q2)
如果我使用n1.childs.append()
,则会出现null约束错误。如果我直接使用n1和n2构造映射器对象,则可以正常工作,但是一旦我访问childs
属性,我将获得无限递归。
编辑:
我发现自定义创建者lambda会导致附加错误。因此更新后的代码如下所示:
from sqlalchemy import Table,'parent')
child_parents = relationship('NodeRelation','child')
def __init__(self,self.childs)
Base.metadata.create_all(engine)
n1 = Node("First")
n2 = Node("Second")
# This is failing with: NOT NULL constraint failed: node_relation.parent_id
n1.childs.append(n2)
session.add(n1)
session.add(n2)
session.commit()
# Node 1 and Node 2 exists
q = session.query(NodeRelation).all()
print(q)
# This is failing with infinite recursion when childs property is displayed.
q2 = session.query(Node).all()
print(q2)
所以唯一的问题是,当我尝试访问childs
属性时,我得到了无限递归。我想我搞砸了一些关系。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。