在datastore中使用反向游标进行分页

标签:Python, Google App Engine

今天在GAE论坛看到一个使用反向游标来分页的方法,觉得很有用,就在此分享了。

关于游标,之前我也介绍过,这里再陈述一番。

先说为什么不用偏移量,而用游标的原因。
如果使用偏移量的话,datastore需要先获取limit + offset个实体,再按偏移量返回limit个实体,于是就多抓取了offset个。这既导致了查询时间的增多,又导致了费用的增加(获取实体数增多),而且当offset超过1000时会被分解为多次查询(很可能遇到超时)。
而使用游标时,就只会抓取limit个实体,不会遇到前面的问题;缺点就是需要上一次查询的游标才能进行下一次查询,因此不能做到从第2页直接跳转到第5页这样的效果。

这个游标在Python SDK中是用google.appengine.datastore.datastore_query.Cursor来表示的。
一个Query或GqlQuery对象在完成fetch或count操作后,就会保存一个Cursor对象用于进行下一次查询。此时,调用这个Query或GqlQuery对象的cursor()方法就能获取到这个Cursor对象编码后的字符串,称为websafe_string(事实上就是进行base64编码)。
通过Cursor.from_websafe_string()方法就能把websafe_string转换成Cursor对象了。

而要进行下一次查询的话,只要保证使用相同的Query或GqlQuery对象,即filter()、order()、ancestor()和fetch()的参数和order()的顺序要完全一致(但是keys_only可以不同),再调用它的with_cursor(websafe_string)方法就能进行下一次查询了。

那么反向游标是什么呢?
这玩意貌似是近期才加进来的,因为之前读源码时我没看到过。其实作用很直白,正向游标就是order()要和前一次查询相同,反向游标则是order()相反,但其余仍要保持一致。
换句话说,正向游标可以实现下一页的功能,反向游标则可以实现上一页的功能。
获取反向游标的方法很简单,先把websafe_string转换成Cursor对象,再调用它的reversed()方法即可。

下面给个例子来演示:
from google.appengine.datastore import datastore_query
from model import Article # 这是我博客的model

query = Article.all(keys_only=True).filter('published =', True).order('time')
print [key.id() for key in query.fetch(10)]

cursor = query.cursor()
print cursor

reversed_cursor = datastore_query.Cursor.from_websafe_string(cursor).reversed().to_websafe_string()
print reversed_cursor

query2 = Article.all(keys_only=True).filter('published =', True).order('-time').with_cursor(reversed_cursor)
print [key.id() for key in query2.fetch(10)]

cursor = query2.cursor()
print cursor

reversed_cursor = datastore_query.Cursor.from_websafe_string(cursor).reversed().to_websafe_string()
print reversed_cursor

结果:
[1183L, 3106L, 3105L, 3104L, 3103L, 3102L, 3101L, 3100L, 3099L, 3098L]
E-ABAOsB8gEEdGltZfoBCQiA4sG19ZeAAuwBggIYagZweS1nYWVyDgsSB0FydGljbGUYmhgMFA==
E-ABAesB8gEEdGltZfoBCQiA4sG19ZeAAuwBggIYagZweS1nYWVyDgsSB0FydGljbGUYmhgMFA==
[3098L, 3099L, 3100L, 3101L, 3102L, 3103L, 3104L, 3105L, 3106L, 1183L]
E-ABAOsB8gEEdGltZfoBCQiA-NS6ko78AewBggIYagZweS1nYWVyDgsSB0FydGljbGUYnwkMFA==
E-ABAesB8gEEdGltZfoBCQiA-NS6ko78AewBggIYagZweS1nYWVyDgsSB0FydGljbGUYnwkMFA==
可以看到,使用反向游标时,因为order的反向反了,或许需要自己对结果进行反向排序处理。

至于究竟怎样把上一页和下一页整合在一起,本文开头给出的代码里就有展示,这里就不copy了。

3条评论 你不来一发么↓ 顺序排列 倒序排列

    向下滚动可载入更多评论,或者点这里禁止自动加载

    想说点什么呢?