Python 如何使用int而不是实例查询sqlalchemy关系?

Python 如何使用int而不是实例查询sqlalchemy关系?,python,orm,sqlalchemy,Python,Orm,Sqlalchemy,我有两个模型,Foo和Bar。Bar与Foo有一对多关系,有一个“Foo_id”列和一个“Foo”关系。我想查询foo_id=1的酒吧行 据我所知,有两种工作方法可以做到这一点: 访问基础外键列对象:query.filter(Bar.foo\u id==1) 获取一个Foo实例,并执行query.filter(Bar.Foo==instance) 我希望这两种方法的替代方法更像query.filter(Bar.foo==1)——也就是说,使用relationship列和普通整数而不是实例。此操作

我有两个模型,Foo和Bar。Bar与Foo有一对多关系,有一个“Foo_id”列和一个“Foo”关系。我想查询foo_id=1的酒吧行

据我所知,有两种工作方法可以做到这一点:

  • 访问基础外键列对象:
    query.filter(Bar.foo\u id==1)
  • 获取一个Foo实例,并执行
    query.filter(Bar.Foo==instance)
  • 我希望这两种方法的替代方法更像
    query.filter(Bar.foo==1)
    ——也就是说,使用relationship列和普通整数而不是实例。此操作当前失败,原因是
    AttributeError:“int”对象没有属性“\u sa\u instance\u state”

    我不想使用上述两种方法的原因:

  • 第一种方法在实际应用程序中不可行,因为我不知道这个
    foo_id
    列的名称-所有表元数据都是通过反射生成的,列名称是我不希望依赖的实现细节(它们目前非常不一致,并且正在使用alembic迁移重命名,因此不希望依赖于这些名称)

  • 第二种方法添加了一个额外的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(有效,但我实际上不知道foo_id
    开始(隐式)
    选择bar.id作为bar\u id,选择bar.foo\u id作为bar\u foo\u id
    从酒吧
    其中bar.foo_id=?
    限制?抵消?
    (1, 1, 0)
    回降
    --->方法2(有效,但添加了无意义的往返)
    开始(隐式)
    选择foo.id作为foo\u id,选择foo.value作为foo\u value
    来自富
    其中foo.id=?
    (1,)
    选择bar.id作为bar\u id,选择bar.foo\u id作为bar\u foo\u id
    从酒吧
    哪里?=bar.foo\u id
    限制?抵消?
    (1, 1, 0)
    回降
    --->方法3(抛出异常,传递int而不是instance)
    回溯(最近一次呼叫最后一次):
    文件“asd.py”,第51行,在
    乐趣(第1节)
    文件“asd.py”,第19行,在方法_3中
    session.query(Bar.filter)(Bar.foo==some\u foo\u id).first()
    文件“/usr/lib/python2.7/site packages/sqlalchemy/sql/operators.py”,第304行,在__
    返回自操作(eq,其他)
    文件“/usr/lib/python2.7/site packages/sqlalchemy/orm/attributes.py”,第175行,在operate中
    返回op(自比较器,*其他,**kwargs)
    文件“/usr/lib/python2.7/site packages/sqlalchemy/orm/relationships.py”,第1042行,在__
    其他,adapt_source=self.adapter)
    文件“/usr/lib/python2.7/site packages/sqlalchemy/orm/relationships.py”,第1369行,在“优化”比较中
    状态=属性。实例\状态(状态)
    AttributeError:“int”对象没有属性“\u sa\u instance\u state”
    
    找到了一种方法,
    Bar.foo.prop.local\u columns
    是RelationshipProperty的一个属性,它返回一个通常包含一个项的集合(对于像这样的简单关系)。集合是无序的,您不能只获取第一项,因此
    列表(…)[0]
    。完整代码:

    def方法4(会话,一些foo-id):
    foo\u col=list(Bar.foo.prop.local\u列)[0]
    session.query(Bar).filter(foo\u col==some\u foo\u id).first()