SQLAlchemy:使用joinedload进行不必要的连接

时间:2018-01-27 12:19:02

标签: python sqlalchemy

我正在使用SQLAlchemy ORM进行Flask项目,我想在一个急切加载的模型中加入,但这会导致两个连接到同一个中间模型。如果您运行下面的代码,您将在生成的SQL中看到Author模型和Book模型之间有两个连接。如果删除lazy=joined位,则生成的sql是完美的。

我不知道我做错了什么或者这是设计的。在这种情况下,如何在保持joinload的同时让SQLAlchemy发出正确的SQL?

注意:我已经尝试过使用MySQL和SQLite,并且这两种dbs都会发生这种情况。

from sqlalchemy import create_engine, Integer, String, Column
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
Base = declarative_base()

from sqlalchemy import create_engine, Integer, String, Column
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)
Base = declarative_base()


class Author(Base):
    __tablename__ = 'authors'
    id = Column(Integer, primary_key=True)
    name = Column(String)
    pseudo = Column(String)
    books = relationship("Book", lazy='joined')

    def __repr__(self):
        return "<User(name='%s', fullname='%s', password='%s')>" % (
            self.name, self.fullname, self.password)


class Book(Base):
    __tablename__ = 'books'
    id = Column(Integer, primary_key=True)
    author_id = Column(Integer, ForeignKey('authors.id'))
    name = Column(String)
    user = relationship("Author", back_populates="books")
    pages = relationship("Page")


class Page(Base):
    __tablename__ = 'pages'
    id = Column(Integer, primary_key=True)
    book_id = Column(Integer, ForeignKey('books.id'))
    text = Column(String)
    book = relationship("Book", back_populates="pages")


Base.metadata.create_all(engine)
session = Session()

print(str(session.query(Author).outerjoin(Author.books, Page)))

1 个答案:

答案 0 :(得分:1)

这是设计 - 阅读The Zen of Joined Eager Loading

  

了解使用Query.join()来改变查询结果的区别至关重要,joinedload()需要花费很长时间才能更改结果查询,而是隐藏渲染连接的效果,只允许相关对象存在。

中存在多个有些类似的问题,但无法找到符合该法案的问题。

如果您手动添加联接,并希望使用它来急切加载关系,则需要contains_eager()

session.query(Author).\
    outerjoin(Author.books, Book.pages).\
    options(contains_eager(Author.books).contains_eager(Book.pages))

请注意,关系定义Author.booksBook.pages似乎缺少back_populates=参数。