在 SQL Alchemy ORM 中使用辅助连接

Posted

技术标签:

【中文标题】在 SQL Alchemy ORM 中使用辅助连接【英文标题】:Using secondary joins in the SQL Alchemy ORM 【发布时间】:2014-08-08 15:13:57 【问题描述】:

我正在尝试建立从一个表到另外两个表的辅助多对多关系,通过中间的第三个链接到所有三个表。我有两个文件 - 一个用于 ORM 对象 (model.py),一个用于模式对象 (schema.py) 它们看起来像这样:

model.py

import schema
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *



class AbstractBase(object):
    def __repr__(self):
        macros = ["%s=%s" % (key, getattr(self, key, None)) for key in self.__table__.columns.keys()]
        rep = "<%s(%s)>" % (self.__class__.__name__, str.join(', ', macros))
        return rep

Base = declarative_base(cls=AbstractBase)


class A(Base):
    __table__ = schema.a_table
    dees = relationship("D", 
                       secondary=schema.b_table,
                       primaryjoin="A.a_id==b_table.c.a_id",
                       secondaryjoin="b_table.c.c_id==D.d_id")
    cees = relationship("C", 
                         secondary=schema.b_table,
                         primaryjoin="A.a_id==schema.b_table.c.a_id",
                         secondaryjoin="b_table.c.d_id==C.c_id",
                         backref="a_collection")

class C(Base):
    __table__ = schema.c_table

class D(Base):
    __table__ = schema.d_table

schema.py

from sqlalchemy import *
from sqlalchemy.dialects.mysql import *

metadata = MetaData()

a_table = Table(
    'a',
    metadata,
    Column("a_id", INTEGER(), primary_key=True, nullable=False),
    Column("date", DATETIME(timezone=True)),
)

b_table = Table(
    'shipment_runs',
    metadata,
    Column("a_id", ForeignKey("a.a_id"), primary_key=True,),
    Column("c_id", ForeignKey("c.c_id"), primary_key=True),
    Column("d_id", ForeignKey("d.d_id")),
)

c_table = Table(
    'c',
    metadata,
    Column('c_id', INTEGER(), primary_key=True, nullable=False),
    Column('name', VARCHAR(64), unique=True),
)

d_table = Table(
    'd',
    metadata,
    Column('d_id', INTEGER(), primary_key=True, nullable=False)
)

不幸的是,实例化它会导致以下错误:

sqlalchemy.exc.InvalidRequestError:初始化映射器 Mapper|A|a 时,表达式 'A.a_id==b_table.c.a_id' 未能找到名称(“名称 'b_table' 未定义”)。如果这是一个类名,请考虑在定义了两个依赖类之后将此 relationship() 添加到该类中。

有没有办法可以更改我的导入或让映射器以某种方式了解架构模块中的对象?

【问题讨论】:

【参考方案1】:

通过以下方式获得它:

class B(Base):
    __table__ = schema.b_table


class A(Base):
    __table__ = schema.a_table
    dees = relationship("D", 
                      secondary=b.__table__,
                      primaryjoin="A.a_id==B.a_id",
                      secondaryjoin="B.c_id==D.d_id")
    cees = relationship("C", 
                        secondary=B.__table__,
                        primaryjoin="A.a_id==B.a_id",
                        secondaryjoin="B.d_id==C.c_id",
                        backref="a_collection")

所有功劳都归于这个问题:

SQLAlchemy Relationship Error: object has no attribute 'c'

【讨论】:

【参考方案2】:

一般情况下,您可以在字符串中使用 名称,或者删除字符串并使用您的实际引用。

primaryjoin="A.a_id==shipment_runs.c.a_id",

primaryjoin=schema.a_table.c.a_id==schema.b_table.c.a_id,

话虽如此,鉴于您在表中设置了ForeignKeys,SQLAlchemy 足够聪明,您甚至不需要连接来建立简单的关系,只需secondary

c_list = relationship("C", secondary=schema.b_table, backref="a_list")

(我认为在您的示例中交换了“C”和“D”?)

【讨论】:

谢谢!交换是我在匿名代码时犯的一个错误 - 它已得到修复。

以上是关于在 SQL Alchemy ORM 中使用辅助连接的主要内容,如果未能解决你的问题,请参考以下文章

向已有 select_from() 的 SQL Alchemy 表达式添加连接

数据库连接对象不是 Python Django SQL Alchemy 数据库池引发的可调用异常。为啥?

安装了sql-alchemy但导入sql_alchemy时失败

使用 SQL Alchemy 和 pymssql 指定故障转移伙伴

SQL Alchemy奇怪的行为从同一个表中加入多个列

使用blob在python中将pdf上传到sql-alchemy