如何在Flask-SqlAlchemy中使用子查询?

时间:2014-08-15 09:52:37

标签: flask sqlalchemy subquery flask-sqlalchemy

query_1 = db\
    .Query([UserModel, func.count(FriendModel.friend_id)])\
    .select_from(UserModel)\
    .outerjoin(FriendModel, and_(UserModel.id==FriendModel.user_id))\
    .group_by(FriendModel.user_id)
  s_1 = query_1.subquery('s_1')
  print s_1.c.id
  query_2 = db\
    .Query(FriendModel)\
    .select_from(FriendModel)\
    .outerjoin(s_1, FriendModel.user_id==s_1.c.id)

帮助同时获得两个查询。 https://gist.github.com/vlikin/17d53440eeef7f4147b2

I receive such errors:
InvalidRequestError: SQL expression, column, or mapped entity expected - got '[<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x7f2e28e1b810>, <sqlalchemy.sql.functions.count at 0x7f2e236c3ed0; count>]'

AttributeError: Neither ‘count’ object nor ‘Comparator’ object has an attribute ‘_autoflush’

我也有问题因为db.Query而不是db.session.query。我想使用db.Query,因为它有分页:)

谢谢。

1 个答案:

答案 0 :(得分:3)

我遇到了完全相同的问题。

我对此问题的解决方案是直接使用db.session.query并创建flask_sqlalchemy.Pagination的新子类。子类包含一个允许我从任何查询创建Pagination对象的方法。

from flask import abort
from flask_sqlalchemy import Pagination as _Pagination

class Pagination(_Pagination):
    """Extend Pagination class to let us construct it from any BaseQuery."""
    @classmethod
    def from_query(cls, query, page, per_page, error_out=True):
        """Returns `per_page` items from page `page`.  By default it will
        abort with 404 if no items were found and the page was larger than
        1.  This behavor can be disabled by setting `error_out` to `False`.

        This is basically a copy of flask_sqlalchemy.Query.paginate()

        Returns an :class:`Pagination` object.
        """
        if error_out and page < 1:
            abort(404)
        items = query.limit(per_page).offset((page - 1) * per_page).all()
        if not items and page != 1 and error_out:
            abort(404)

        # No need to count if we're on the first page and there are fewer
        # items than we expected.
        if page == 1 and len(items) < per_page:
            total = len(items)
        else:
            total = query.order_by(None).count()

        return cls(query, page, per_page, total, items)

现在根据以下代码段使用它:

query = db.session.query(…)
pagination = Pagination.from_query(query, page, 20)

首先,问题是从Pagination创建db.Query - 对象的主要逻辑不是Pagination类的一部分,而是在db.Query.paginate()中实现。