下面的示例代码(基于SQLAlchemy ORM tutorial):
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship, backref
from sqlalchemy.orm import sessionmaker
from sqlalchemy import func
engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship("User", backref=backref('addresses', order_by=id))
Base.metadata.create_all(engine)
if __name__ == "__main__":
session = Session()
query = session.query(func.count(User.id)).join(User.addresses)
运行良好的之前的0.8版本SQLAlchemy的。但是,对于版本> = 0.8时,它产生了以下错误:
AttributeError: type object 'User' has no attribute 'addresses'
这不会的情况下,最后一行是发生:
query = session.query(User).join(User.addresses)
然而,func
表达的使用是the preferred way to issue 'count' queries根据SQLAlchemy的文档(以及也参见zzzeek's answer here)。它真正的问题在大表的情况。
所以,我明白,这个问题是因为在new way relationships work since version 0.8的。现在的问题是,什么应该是正确的(也是最有效的)的方式来“强制” backref初始化。
注:与映射的类作为参数发出的第一个查询后,backrefs将被初始化,这样所有其他的查询将不会面临上述问题。问题的关键是,在发出func.count
查询时,我不知道是否backrefs已经初始化或没有(即这是第一次发出查询)。
你举的例子是完全一样的,在SQLAlchemy的文档的Linking Relationships with Backref部分。第二个代码块显示了使用equivalent
参数的back_populates
版本。但是,在这种情况下,关系的双方都初始化和您的查询应该工作。随着order_by
你的模型应该是这样的:
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address", order_by="Address.id", back_populates="user")
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship( "User", back_populates="addresses")