在SQL Alchemy ORM中使用辅助连接

时间:2014-08-08 15:13:57

标签: python orm sqlalchemy

我正在尝试建立从一个表到另外两个表之间的次要多对多关系,通过连接到所有三个表的中间的第三个。我有两个文件 - 一个用于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”找不到名称(“name'b_table'未定义”)。如果这是一个类名,请考虑在定义了两个依赖类之后将此关系()添加到类中。

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

2 个答案:

答案 0 :(得分:2)

能够通过以下方式获得它:

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'

答案 1 :(得分:1)

通常,您可以在字符串中使用名称,或删除字符串并使用实际引用。

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

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

话虽如此,鉴于您在表中设置了ForeignKey,SQLAlchemy足够聪明,您甚至不需要简单关系的连接,只需secondary。< / p>

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

(我认为你的例子中交换了“C”和“D”)。