Skip to main content
 首页 » 编程设计

python之我如何在 sqlalchemy 中连接两个 ORM 表,但返回两列

2025年05月04日13xiaohuochai

我有一些代码看起来非常像这样:

import sqlalchemy as sa 
from sqlalchemy.ext.declarative import declarative_base 
 
engine = sa.create_engine('sqlite:///:memory:', echo=True) 
Base = declarative_base() 
 
 
class OneThing(Base): 
    __tablename__ = 'one' 
 
    id = sa.Column(sa.Integer, primary_key=True) 
    name = sa.Column(sa.Text) 
    value = sa.Column(sa.Text) 
 
 
class OtherThing(Base): 
    __tablename__ = 'other' 
 
    id = sa.Column(sa.Integer, primary_key=True) 
    some_deal = sa.Column(sa.Text) 
    other_deal = sa.Column(sa.Text) 
 
Base.metadata.create_all(engine) 
 
session = sa.orm.sessionmaker(bind=engine)() 
one = OneThing() 
one.id = 42 
one.name = 'hi' 
one.value = 'roscivs' 
session.add(one) 
other = OtherThing() 
other.id = 42 
other.some_deal = 'brown' 
other.other_deal = 'and sticky' 
session.add(other) 
session.commit() 

现在,我可以运行以下命令:

for row in session.query(OneThing).outerjoin(OtherThing, OneThing.id == OtherThing.id): 
    print(row) 

它会打印一行。显然我没有 __repr__ 所以它只会打印出非常难看的默认 repr。但是假设我想要 other_deal 值,所以我输入了 print(row.other_deal)。

我收到以下错误:

Traceback (most recent call last): 
  File "test.py", line 43, in <module> 
    print(row.other_deal) 
AttributeError: 'OneThing' object has no attribute 'other_deal' 

事实上,您可以看到发出的 SQL 并不是我想要的:

SELECT one.id AS one_id, one.name AS one_name, one.value AS one_value 
FROM one LEFT OUTER JOIN other ON one.id = other.id 

它正在 进行外部连接...但它只返回one 表中的列。我想要一个 和 other。我如何获得它?

我试过了 add_entity ,但这并没有达到我想要的效果。

关于如何从两个模型中获取列的任何线索? (注意,我不能在两个表之间添加ForeignKey关系)

请您参考如下方法:

首先从其他事情开始,我们将开始回答您的实际问题。

首先,declarative_base 提供了一个关键字参数构造器,所以不是这样的:

one = OneThing() 
one.id = 42 
one.name = 'hi' 
one.value = 'roscivs' 

你可以这样写:

one = OneThing(id=42, name='hi', value='roscivs') 

其次:假设两个表之间存在数据库关系,可以使用relationship定义来通知sqlalchemy两者之间的关系楷模。这里我假设从id列到id列有一个ForeignKey,并且是一对一的关系:

class OtherThing(Base): 
    ... 
    id = sa.Column(sa.Integer, sa.ForeignKey(OneThing.id), primary_key=True) 
    ... 
    one_thing = sa.orm.relationship(OneThing, backref=sa.orm.backref('other_thing', uselist=False)) 

在这种情况下,您可以按如下方式编写当前查询,sqlalchemy 将找出连接条件:

query = session.query(OneThing).outerjoin(OtherThing) 

最后,让我们在结果中加入相关数据。有多种选择,但从您所拥有的开始,您可以查询 OneThing(仅),然后导航如上定义的关系:

query = session.query(OneThing).outerjoin(OtherThing) 
for one in query: 
    print(one) 
    print(one.other_thing.other_deal) 

另一种选择是同时查询两个模型,但请注意结果行包含 (OneThing, OtherThing) 的元组:

query = session.query(OneThing, OtherThing).outerjoin(OtherThing) 
for one, oth in query: 
    print(one) 
    print(oth) 

另一种选择是只查询列的子集:

query = session.query(OneThing.name, OtherThing.other_deal).outerjoin(OtherThing) 
for row in query: 
    print(row) 
# ('hi', 'and sticky')