8

アイデア/代替案の検索から、GAEデータストアクエリに一致するアイテムのページ/アイテム数/ナビゲーションの提供まで、 REVERSINGORDERによって単一のカーソルでページナビゲーションを逆方向にする方法のヒントを見つけることができました。

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

これらの複数のカーソルに加えて、順方向および逆方向のクエリを処理するのは複雑すぎるだけでなく、「<< 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

paging最後に、Jinja2 を使用している場合は、 dictを使用したページング ナビゲーションを次に示します。

{% 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 に答える