sqlalchemy 分页
我正在用Flask和SQLAlchemy构建一个REST应用,遇到了一个问题。我想查询所有用户以及他们的书籍数量。每个用户都有很多书,所以我的查询应该返回每个用户拥有的书籍数量。
// Models
class User( object ):
__tablename__ = 'user'
class Book( object ):
__tablename__ = 'book'
// Metadata
users_table = Table( 'user', metadata,
Column( 'id', Integer, primary_key = True ),
Column( 'username', String( 50 ), unique = True )
)
books_table = Table( 'book', metadata,
Column( 'id', Integer, primary_key = True ),
Column( 'title', String( 50 ) ),
Column( 'user_id', Integer, ForeignKey( 'user.id' ) )
)
// Mappers
mapper( User, users_table, properties = {
'booksCount': column_property(
select(
[func.count( books_table.c.id )],
books_table.c.user_id == users_table.c.id
).label( 'booksCount' )
),
'books' : relationship( Book )
} )
mapper( Book, books_table, properties = {
'user': relationship( User )
} )
如果我想查询所有用户,这个查询可以正常工作,并且会返回带有'booksCount'(书籍数量)的结果,这样没问题。但是如果我想更进一步,比如只查询那些'booksCount'大于4的用户,这就变得复杂了,因为我还需要在应用限制和偏移之前知道总的结果数量,这样我的分页功能才能正常工作。
// this works
rows = User.query
totalRows = rows.count ()
users = rows.limit( 50 ).offset( 0 ).all()
for user in users:
...
// this throws an error
rows = User.query.having('booksCount>4')
totalRows = rows.count ()
users = rows.limit( 50 ).offset( 0 ).all()
第二个例子出错的原因是因为 totalRows = rows.count ()
这行代码会创建一个新的查询来计算结果的数量:SELECT count(1) AS count_1 FROM user
。但是当在查询中加入 having
时,它就变成了 SELECT count(1) AS count_1 FROM user having booksCount>4
,这显然会出错,因为在这个第二个查询中并没有选择booksCount。
那么,我该如何在应用了 having
子句的选择中提取总行数呢?
谢谢。
2 个回答
这其实是一个SQL语法错误。having
这个部分只有在你同时使用了 group by
的时候才能用,而且它只用来过滤聚合结果。你需要的是一个简单的 where
语句,可以这样写:
rows = User.query.filter(User.booksCount > 4)
顺便提一下,请按照Python的标准来写代码,比如 User.books_count
我来给自己解答一下,顺便把解决办法分享给其他遇到同样问题的人。如果你在用Ubuntu系统,并且是从软件库安装的sqlalchemy,建议你先把它卸载掉,然后去sqlalchemy的官方网站,按照那里的说明重新安装。现在的新版本(目前是0.7.1)已经修复了这个问题。
Ubuntu自带的是0.6.4版本。