以下示例代码(基于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)
但是,根据SQLAlchemy文档,func
表达式的用法为the preferred way to issue 'count' queries(另请参阅zzzeek's answer here)。对于大型桌子来说,它确实很重要。
所以,我知道这个问题是因为new way relationships work since version 0.8而发生的。问题是,“强制执行”backref初始化的正确(和最有效)方法应该是什么。
注意:在使用映射类作为参数发出第一个查询之后,将初始化backrefs,以便所有其他查询不会遇到上述问题。关键是,在发出func.count
查询时,我不知道backrefs是否已经初始化(即这是第一次发出查询)。
答案 0 :(得分:1)
您的示例与SQLAlchemy文档的Linking Relationships with Backref部分中的示例完全相同。第二个代码块使用back_populates
参数显示equivalent
版本。但在这种情况下,关系的两端都已初始化,您的查询应该可以正常工作。使用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")