2009-11-07 14 views
5

Ho una pagina basata su un oggetto modello e desidero avere collegamenti alle pagine precedenti e successive. Non mi piace la mia soluzione attuale perché richiede la valutazione dell'intero queryset (per ottenere l'elenco ids) e quindi altre due query get. Sicuramente c'è un modo in cui questo può essere fatto in un solo passaggio?Come posso ottenere oggetti precedenti e successivi da un set di filtri, ordinato?

def get_prev_and_next_page(current_page): 
    ids = list(Page.objects.values_list("id", flat=True)) 
    current_idx = ids.index(current_page.id) 
    prev_page = Page.objects.get(id=ids[current_idx-1]) 
    try: 
     next_page = Page.objects.get(id=ids[current_idx+1]) 
    except IndexError: 
     next_page = Page.objects.get(id=ids[0]) 
    return (prev_page, next_page) 

Ordina ordine definito nel modello, quindi non c'è bisogno di essere trattati qui, ma notare che non si può supporre che gli ID sono sequenziali.

risposta

8

Suona come qualcosa che l'impaginatore impostato su una soglia di 1 farebbe bene.

# Full query set... 
pages = Page.objects.filter(column=somevalue) 
p = Paginator(pages, 1) 

# Where next page would be something like... 
if p.has_next(): 
    p.page(p.number+1) 

Documentation here e here.

+1

Grazie, ero vagamente consapevole della Paginator, ma non avevo capito che ho potuto usarlo come quello (cioè con una soglia di 1, in effetti solo avvolgendo il queryset in un oggetto Paginator con i metodi 'has_next()', 'has_previous()'). L'unica cosa che manca è che non inizi all'inizio dell'intervallo di paginator, ma sembra che posso ottenere questo con 'p.object_list.index (start_page)'. –

+1

Questo ha finito per non funzionare bene per me. La classe Paginator in realtà non è fatta per attraversare gli oggetti. –

1

Sono nuovo di Python e Django, quindi forse il mio codice non è ottimale, ma check this out:

def get_prev_and_next_items(target, items): 
    ''' To get previous and next objects from QuerySet ''' 
    found = False 
    prev = None 
    next = None 
    for item in items: 
     if found: 
      next = item 
      break 
     if item.id == target.id: 
      found = True 
      continue 
     prev = item 
    return (prev, next) 

e in vista una cosa del genere:

def organisation(request, organisation_id): 
    organisation = Organisation.objects.get(id=organisation_id) 
    ... 
    prev, next = get_prev_and_next_items(organisation, Organisation.objects.all().order_by('type')) 
    ... 
    return render_to_response('reference/organisation/organisation.html', { 
     'organisation': organisation, 
     'prev': prev, 
     'next': next, 
    }) 

Sicuramente non ottimale per i queryset «pesanti», ma nella maggior parte dei casi funziona come un incantesimo. :)

1

Verificare django-next-prev, l'ho scritto per risolvere questo problema esatto. In questo caso:

from next_prev import next_in_order, prev_in_order 

def get_prev_and_next_page(current_page): 
    page_qs = Page.objects.all() # this could be filtered, or ordered 
    prev_page = prev_in_order(current_page, page_qs) 
    next_page = prev_in_order(current_page, page_qs) 
    return (prev_page, next_page) 
Problemi correlati