[英]How to build many-to-many relations using SQLAlchemy: a good example
我已经阅读了有关构建多对多关系的 SQLAlchemy 文档和教程,但是当关联表包含超过 2 个外键时,我无法弄清楚如何正确执行此操作。
我有一个项目表,每个项目都有很多细节。 许多项目的详细信息可以相同,因此项目和详细信息之间存在多对多关系
我有以下几点:
class Item(Base):
__tablename__ = 'Item'
id = Column(Integer, primary_key=True)
name = Column(String(255))
description = Column(Text)
class Detail(Base):
__tablename__ = 'Detail'
id = Column(Integer, primary_key=True)
name = Column(String)
value = Column(String)
我的关联表是(它在代码中的其他 2 个之前定义):
class ItemDetail(Base):
__tablename__ = 'ItemDetail'
id = Column(Integer, primary_key=True)
itemId = Column(Integer, ForeignKey('Item.id'))
detailId = Column(Integer, ForeignKey('Detail.id'))
endDate = Column(Date)
在文档中,据说我需要使用“关联对象”。 我不知道如何正确使用它,因为它混合了声明性和映射器表单,并且示例似乎不完整。 我添加了以下行:
details = relation(ItemDetail)
作为 Item 类和行的成员:
itemDetail = relation('Detail')
作为关联表的成员,如文档中所述。
当我执行 item = session.query(Item).first() 时,item.details 不是 Detail 对象的列表,而是 ItemDetail 对象的列表。
如何在 Item 对象中正确获取详细信息,即 item.details 应该是 Detail 对象的列表?
从评论中我看到你找到了答案。 但SQLAlchemy文档对于“新用户”而言非常压倒性,而我正在努力解决同样的问题。 所以供将来参考:
ItemDetail = Table('ItemDetail',
Column('id', Integer, primary_key=True),
Column('itemId', Integer, ForeignKey('Item.id')),
Column('detailId', Integer, ForeignKey('Detail.id')),
Column('endDate', Date))
class Item(Base):
__tablename__ = 'Item'
id = Column(Integer, primary_key=True)
name = Column(String(255))
description = Column(Text)
details = relationship('Detail', secondary=ItemDetail, backref='Item')
class Detail(Base):
__tablename__ = 'Detail'
id = Column(Integer, primary_key=True)
name = Column(String)
value = Column(String)
items = relationship('Item', secondary=ItemDetail, backref='Detail')
以前的答案对我有用,但我对表 ItemDetail 使用了类基方法。 这是示例代码:
class ItemDetail(Base):
__tablename__ = 'ItemDetail'
id = Column(Integer, primary_key=True, index=True)
itemId = Column(Integer, ForeignKey('Item.id'))
detailId = Column(Integer, ForeignKey('Detail.id'))
endDate = Column(Date)
class Item(Base):
__tablename__ = 'Item'
id = Column(Integer, primary_key=True)
name = Column(String(255))
description = Column(Text)
details = relationship('Detail', secondary=ItemDetail, backref='Item')
class Detail(Base):
__tablename__ = 'Detail'
id = Column(Integer, primary_key=True)
name = Column(String)
value = Column(String)
items = relationship('Item', secondary=ItemDetail, backref='Detail')
像 Miguel 一样,我也在我的连接表中使用声明式方法。 但是,我一直遇到错误,例如
sqlalchemy.exc.ArgumentError:传递给relationship() User.projects 的次要参数<class ' main .ProjectUser'> 必须是Table 对象或其他FROM 子句; 不能直接发送映射类,因为“辅助”中的行独立于映射到同一个表的类而持久化。
通过一些摆弄,我能够想出以下内容。 (请注意,我的课程与 OP 不同,但概念是相同的。)
这是一个完整的工作示例
from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import declarative_base, relationship, Session
# Make the engine
engine = create_engine("sqlite+pysqlite:///:memory:", future=True, echo=False)
# Make the DeclarativeMeta
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
name = Column(String)
projects = relationship('Project', secondary='project_users', back_populates='users')
class Project(Base):
__tablename__ = "projects"
id = Column(Integer, primary_key=True)
name = Column(String)
users = relationship('User', secondary='project_users', back_populates='projects')
class ProjectUser(Base):
__tablename__ = "project_users"
id = Column(Integer, primary_key=True)
notes = Column(String, nullable=True)
user_id = Column(Integer, ForeignKey('users.id'))
project_id = Column(Integer, ForeignKey('projects.id'))
# Create the tables in the database
Base.metadata.create_all(engine)
# Test it
with Session(bind=engine) as session:
# add users
usr1 = User(name="bob")
session.add(usr1)
usr2 = User(name="alice")
session.add(usr2)
session.commit()
# add projects
prj1 = Project(name="Project 1")
session.add(prj1)
prj2 = Project(name="Project 2")
session.add(prj2)
session.commit()
# map users to projects
prj1.users = [usr1, usr2]
prj2.users = [usr2]
session.commit()
with Session(bind=engine) as session:
print(session.query(User).where(User.id == 1).one().projects)
print(session.query(Project).where(Project.id == 1).one().users)
secondary
参数中引用表名,如secondary='project_users'
而不是secondary=ProjectUser
back_populates
而不是backref
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.