8

寻找想法/替代方案到提供与 GAE 数据存储查询匹配的项目的页面/项目计数/导航,我可以找到提示如何通过 REVERSING ORDER 使用单个光标向后页面导航。

class CursorTests(test_utils.NDBTest):

  def testFirst(self):
    class Bar(model.Model):
      value = model.IntegerProperty()

    self.entities = []
    for i in range(10):
        e = Bar(value=i)
        e.put()
        self.entities.append(e)

    q = Bar.query()
    bars, next_cursor, more = q.order(Bar.key).fetch_page(3)
    barz, another_cursor, more2 = q.order(-Bar.key).fetch_page(3, start_cursor=next_cursor)
    self.assertEqual(len(bars), len(barz))

不幸的是,它因此错误而失败。

回溯(最近一次通话最后):文件“/Users/reiot/Documents/Works/appengine-ndb-experiment/ndb/query_test.py”,第 32 行,在 testFirst self.assertEqual(len(bars), len(baz) ) AssertionError: 3 != 2

是的,反向查询缺少边界中的项目。

bars = [Bar(key=Key('Bar', 1), value=0), Bar(key=Key('Bar', 2), value=1), Bar(key=Key('Bar', 3), value=2)] 
bars = [Bar(key=Key('Bar', 2), value=1), Bar(key=Key('Bar', 1), value=0)]

我该如何解决这个问题?

4

2 回答 2

15

好的,这是官方的答案。您需要“反转”光标,如下所示:

rev_cursor = cursor.reversed()

我自己不知道这一点。:-( 我会确保这显示在 fetch_page() 的文档中。

于 2012-04-22T15:02:25.597 回答
2

处理这些多个游标,加上正向和反向查询,不仅太复杂,而且不允许直接分页(转到第7页),在页面底部有一组页面链接像这样“<< 1 2 3 4 5 >>",因为你不知道会有多少页。

出于这个原因,我的解决方案是获取整个结果集,或者至少是一个重要的结果集,例如对应于 10 个页面,然后进行简单的划分来处理页面。为了不浪费 Ndb 带宽(和成本),您将首先使用keys_only=True. 在确定与当前页面对应的集合后,您可以key.get()在实体上执行此操作。如果你愿意,你可以考虑将完整的键列表保存在 memcache 中几分钟,这样查询就不会重新运行,尽管到目前为止我还没有发现这是必要的。

这是一个示例实现:

def session_list():
    page = request.args.get('page', 0, type=int)

    sessions_keys = Session.query().order(-Session.time_opened).fetch(100, keys_only=True)
    sessions_keys, paging = generic_list_paging(sessions_keys, page)
    sessions = ndb.get_multi(sessions_keys)

    return render_template('generic_list.html', objects=sessions, paging=paging)

它使用了一个generic_list_paging函数来进行分页划分并在结果集中提取正确的子列表:

def generic_list_paging(objects, page, page_size=10):
    nb_items = len(objects)
    item_start = min(page * page_size, nb_items)
    item_end = min((page + 1) * page_size, nb_items)
    page_max = (nb_items - 1) // page_size + 1
    objects = objects[item_start: item_end]
    paging = {'page': page, 'page_max': page_max}
    return objects, paging

最后,如果您使用的是 Jinja2,这里是使用pagingdict 的分页导航:

{% if paging.page_max > 1 %}
        <nav>
            <ul class="pagination">
                {% if paging.page > 0 %}
                    <li>
                        <a href="{{ request.path }}?page={{ paging.page-1 }} aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span>
                        </a>
                    </li>
                {% endif %}
                {% for page in range(0,paging.page_max) %}
                    <li {% if page==paging.page %}class="disabled"{% endif %}><a href="{{ request.path }}?page={{ page }}">{{ page+1 }}</a></li>
                {% endfor %}
                {% if paging.page < paging.page_max-1 %}
                    <li>
                        <a href="{{ request.path }}?page={{ paging.page+1 }}" aria-label="Next">
                            <span aria-hidden="true">&raquo;</span>
                        </a>
                    </li>
                {% endif %}
            </ul>
        </nav>
{% endif %}
于 2015-04-10T13:39:08.983 回答