我有兩個模型,Foo和Bar。 Bar與Foo有一個一對多的關係,有一個「foo_id」列和一個「foo」關係。我想查詢具有foo_id = 1的Bar的行。如何使用int而不是實例查詢sqlalchemy關係?
據我所知,有兩種工作方式做到這一點:
- 訪問底層外鍵字段對象:
query.filter(Bar.foo_id == 1)
- 獲得美孚的一個實例,並做
query.filter(Bar.foo == instance)
我想替代這兩種方法更像query.filter(Bar.foo == 1)
- 也就是說,使用關係列,一個純整數,而不是一個實例。目前這失敗AttributeError: 'int' object has no attribute '_sa_instance_state'
原因,我想避免這兩種方法上面:
第一種方法是不是在實際應用中是可行的,因爲我不知道這個名字
foo_id
列 - 所有表元數據都是通過反射生成的,而列名是我不想依賴的實現細節(它們目前非常不一致,並且在使用alembic遷移進行重命名的過程中,所以對這些名稱的依賴關係是不可取的)第二次見面hod增加了一個額外的SQL查詢往返取Foo的一個實例之前,我能夠做的實際查詢不使用任何比我已經有的整數ID(和身份地圖沒有它緩存與我使用它的方式)。我承認這一部分危險地接近不成熟的優化,但仍然感到浪費,應該有更好的方法。
另一種方式來短語這個問題是如何到達外鍵列從RelationshipProperty開始,可能使用內省
我還可以用罰款的方式來得到某種延遲加載的Foo例如這是足以讓通過ID查詢,但實際上並沒有發送SQL查詢
下面是說明問題的一些自包含的測試代碼:
from sqlalchemy import create_engine, Column, Integer, ForeignKey
from sqlalchemy.orm import relationship, Session
from sqlalchemy.ext.declarative import declarative_base
def method_1(session, some_foo_id):
"""Works, but i don't actually know foo_id"""
session.query(Bar).filter(Bar.foo_id == some_foo_id).first()
def method_2(session, some_foo_id):
"""Works, but adds a pointless roundtrip"""
some_foo = session.query(Foo).get(some_foo_id)
session.query(Bar).filter(Bar.foo == some_foo).first()
def method_3(session, some_foo_id):
"""Throws an exception, passing int instead of instance"""
session.query(Bar).filter(Bar.foo == some_foo_id).first()
# database setup follows
Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)
value = Column(Integer)
class Bar(Base):
__tablename__ = 'bar'
id = Column(Integer, primary_key=True)
foo_id = Column(Integer, ForeignKey('foo.id'))
foo = relationship(Foo)
if __name__ == '__main__':
engine = create_engine('sqlite://')
Base.metadata.create_all(engine)
session = Session(bind=engine)
foo1, foo2 = Foo(value=1), Foo(value=2)
bar1, bar2 = Bar(foo=foo1), Bar(foo=foo2)
session.add_all([foo1, foo2, bar1, bar2])
session.commit()
engine.echo = True
for fun in [method_1, method_2, method_3]:
print("\n---> %s (%s)\n" % (fun.__name__, fun.__doc__))
fun(session, 1)
session.rollback()
輸出:
---> method_1 (Works, but i don't actually know foo_id
BEGIN (implicit)
SELECT bar.id AS bar_id, bar.foo_id AS bar_foo_id
FROM bar
WHERE bar.foo_id = ?
LIMIT ? OFFSET ?
(1, 1, 0)
ROLLBACK
---> method_2 (Works, but adds a pointless roundtrip)
BEGIN (implicit)
SELECT foo.id AS foo_id, foo.value AS foo_value
FROM foo
WHERE foo.id = ?
(1,)
SELECT bar.id AS bar_id, bar.foo_id AS bar_foo_id
FROM bar
WHERE ? = bar.foo_id
LIMIT ? OFFSET ?
(1, 1, 0)
ROLLBACK
---> method_3 (Throws an exception, passing int instead of instance)
Traceback (most recent call last):
File "asd.py", line 51, in <module>
fun(session, 1)
File "asd.py", line 19, in method_3
session.query(Bar).filter(Bar.foo == some_foo_id).first()
File "/usr/lib/python2.7/site-packages/sqlalchemy/sql/operators.py", line 304, in __eq__
return self.operate(eq, other)
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 175, in operate
return op(self.comparator, *other, **kwargs)
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1042, in __eq__
other, adapt_source=self.adapter))
File "/usr/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1369, in _optimized_compare
state = attributes.instance_state(state)
AttributeError: 'int' object has no attribute '_sa_instance_state'