dud*_*ein 13 python many-to-many sqlalchemy associations
我已经阅读了关于构建多对多关系的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)
Run Code Online (Sandbox Code Playgroud)
我的关联表是(它在代码中的其他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)
Run Code Online (Sandbox Code Playgroud)
在文档中,据说我需要使用"关联对象".我无法弄清楚如何正确使用它,因为它与mapper表单混合声明,并且示例似乎不完整.我添加了这一行:
details = relation(ItemDetail)
Run Code Online (Sandbox Code Playgroud)
作为Item类和行的成员:
itemDetail = relation('Detail')
Run Code Online (Sandbox Code Playgroud)
作为关联表的成员,如文档中所述.
当我执行item = session.query(Item).first()时,item.details不是Detail对象的列表,而是ItemDetail对象的列表.
如何在Item对象中正确获取详细信息,即item.details应该是Detail对象的列表?
Ben*_*Ben 36
与 Miguel 一样,我也对连接表使用声明式方法。但是,我不断遇到类似的错误
sqlalchemy.exc.ArgumentError:辅助参数<class ' main .ProjectUser'>传递给relationship() User.projects必须是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)
Run Code Online (Sandbox Code Playgroud)
secondary在参数中引用表名,secondary='project_users'而不是secondary=ProjectUserback_populates而不是backref我在这里对此做了详细的文章。
ker*_*rma 13
从评论中我看到你找到了答案.但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')
Run Code Online (Sandbox Code Playgroud)
Mig*_*les 11
上一个答案对我有用,但我对表 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.__table__, backref='Item')
class Detail(Base):
__tablename__ = 'Detail'
id = Column(Integer, primary_key=True)
name = Column(String)
value = Column(String)
items = relationship('Item', secondary=ItemDetail.__table__, backref='Detail')
Run Code Online (Sandbox Code Playgroud)