2012-04-20 9 views
8

Da looking for ideas/alternatives to providing a page/item count/navigation of items matching a GAE datastore query, ho trovato un suggerimento su come spostarsi indietro della pagina con un solo cursore di INVERSIONE DELL'ORDINE.L'impaginazione all'indietro con il cursore funziona ma manca un elemento

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)) 

Sfortunatamente non è riuscito con questo errore.

Traceback (most recent call last): File "/Users/reiot/Documents/Works/appengine-ndb-experiment/ndb/query_test.py", line 32, in testFirst self.assertEqual(len(bars), len(baz)) AssertionError: 3 != 2

Sì, manca una voce in bound con query inversa.

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)] 

Come posso risolvere questo problema?

+1

Buona domanda. L'ho confermato. Ho chiamato gli esperti. Si comporta anche in questo modo sul datastore di produzione? –

risposta

14

Ok, ecco la risposta ufficiale. È necessario "invertire" il cursore, come segue:

rev_cursor = cursor.reversed() 

Non lo sapevo da solo. :-(Mi assicurerò che ciò venga mostrato nei documenti per fetch_page().

+1

Grazie! buono a sapersi la soluzione ufficiale per questo :-) –

+0

Questo è voglio che sto cercando da anni nella documentazione o notizie :) – Chameleon

+1

I documenti sono stati a lungo risolti. Vedi https://developers.google.com/appengine/docs/python/ndb/queries#cursors (verso la fine di quella sezione). –

2

Gestire questi cursori multipli, oltre alle query di inoltro e inverso non solo è troppo complicato, ma non consente il paging diretto (andare alla pagina 7), con una serie di link alle pagine nella parte inferiore della pagina in questo modo "< < 1 2 3 4 5 >>", dal momento che non avete idea di quante pagine ci saranno.

Per questo motivo, la mia soluzione sarebbe quello di recuperare l'intero set di risultati, o almeno un set di risultati significativo, ad esempio corrispondente a 10 pagine, quindi fare semplici divisioni per gestire le pagine.Per non sprecare larghezza di banda Ndb (e costi), si dovrebbe prima recuperare i risultati con keys_only=True. Dopo aver determinato il set che corrisponde a te r pagina corrente, esegui lo key.get() sulle tue entità. E se vuoi, puoi considerare di salvare l'elenco completo delle chiavi in ​​memcache per alcuni minuti, in modo che la query non venga rieseguita, anche se non ho trovato che sia necessario fino ad ora.

Questo è un esempio di implementazione:

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) 

Sta facendo uso di una funzione generic_list_paging che fa le divisioni di paging e l'estrazione della sottolista corretta all'interno del set di risultati:

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 

Infine, se si stiamo usando Jinja2, ecco la navigazione di paging usando il paging 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 %} 
+0

Nel codice precedente, session = [sk.get() per sk in sessions_keys] non è buono in termini di prestazioni, dovrebbe essere un get_multi(). L'ho appena risolto – patb

Problemi correlati