Python 如何使用Flask/SQLAlchemy将返回结果的数量限制为仅1000个最新条目?
我正在寻找类似reddit/hackernews(这似乎是许多主要网站的常用方法)处理其“新”列表的方式。它似乎是这样工作的:Python 如何使用Flask/SQLAlchemy将返回结果的数量限制为仅1000个最新条目?,python,caching,sqlalchemy,flask,flask-sqlalchemy,Python,Caching,Sqlalchemy,Flask,Flask Sqlalchemy,我正在寻找类似reddit/hackernews(这似乎是许多主要网站的常用方法)处理其“新”列表的方式。它似乎是这样工作的: 提交新链接时,会抓取一定数量的最新条目 这些查询被每个页面分割,并缓存为cachekey=newestPage1,2,3,4 单击下一个/上一个按钮加载下一个/上一个缓存键 我的问题是:很难找到SQLalchemy/flask SQLalchemy代码,以便只查询最新条目的固定数量 我怎么说: q = PostDB.query(order_by('creation_
- 提交新链接时,会抓取一定数量的最新条目
- 这些查询被每个页面分割,并缓存为cachekey=newestPage1,2,3,4
- 单击下一个/上一个按钮加载下一个/上一个缓存键
q = PostDB.query(order_by('creation_time').desc()).limit(1000)
for chunkOf50Results in q:
cache.set(CachedChunk+=1, chunkOf50Results)
?如果在SQLAlchemy中切片查询,它会自动限制获取的数据库结果集:
limitedQuery = q[:50]
如果您要先获得计数,您可以轻松地循环分组响应:
count = q.count()
for chunkstart in xrange(0, count, 50):
CachedChunk += 1
chunkend = min(chunkstart + 50, count)
cache.set(CachedChunk, q[chunstart:chunkend])
请注意,这确实会导致对数据库的多个查询。或者,您可以使用生成50个项目的组:
from itertools import izip_longest
for chunkOf50Results in izip(*[q.yield_per(50)]*50):
CachedChunk += 1
cache.set(CachedChunk, chunkOf50Results)
我曾经将行预取限制为batchsize,这样就不会预取超过每个批所需的量
izip_longest(*[iterable]*n)
技巧可以从基本迭代器中获得大小为n
的组:
>>> import itertools
>>> list(itertools.izip_longest(*[iter(range(7))]*3))
[(0, 1, 2), (3, 4, 5), (6, None, None)]
请注意,最后一批用None
值填充,以填充到批大小。解决方案是使用技巧
这将导致one访问数据库,获取多达1000篇文章,然后让您将它们分成50个批次并缓存它们。迫不及待地想尝试一下。如果每次发布新条目(更新区块)时都运行此操作,那么当有数百万行要计数时,每次q.count()不是都会变成一个巨大的操作吗?@chrickso:数据库应该优化这种情况。行计数应该很便宜(足够了)。遗憾的是,情况并非总是如此,这取决于所使用的数据库。MySQL尤其臭名昭著,因为在某些情况下每次调用count()时都会扫描整个表。还有其他不依赖“计数”的分页方案,但这些方案显然不能提供可用的总页数。@zzzeek:无论如何,我越来越倾向于
izip_longest
方法。:-)感谢MySQL扫描案例,我很高兴地说,我通常不需要使用该数据库。我如何确保获取的1000个条目是最新的条目,而不是它在达到1000个之前收集的某个随机批次?好吧,我试图理解这里的操作顺序。当我执行q=PostDB.query(order_by('creation_time').desc()).limit(1000)时,我认为这将获得前1000行,然后按创建时间对它们进行排序,而不是确保这1000行是最新的1000@chrickso-不,它按创建时间对整个表进行排序(从最新到最旧),然后从列表中删除前1000个。(事实上,大多数数据库都比这聪明一点,如果可以的话,它们会使用索引来避免对所有内容进行排序)。
q = PostDB.query(order_by('creation_time').desc()).limit(1000)
query_iterators = [iter(q)] * 50
for CachedChunk, chunk_of_50 in enumerate(izip_longest(*query_iterators)):
cache.set(CachedChunk, chunk_of_50)