2010-02-15 15 views
17

Estoy usando Django Forms para hacer una búsqueda filtrada/facetada a través de POST, y me gustaría que la clase de paginador de Django organice los resultados. ¿Cómo conservo la solicitud original al pasar el cliente entre las distintas páginas? En otras palabras, parece que pierdo los datos POST tan pronto como paso la solicitud GET para que otra página regrese a mis puntos de vista. He visto algunas recomendaciones para usar AJAX para actualizar solo el bloque de resultados de la página, pero me pregunto si existe un mecanismo nativo de Django para hacerlo.Paginating the results of Django forms POST request

Gracias.

Respuesta

23

Si desea acceder a los datos de la tienda en una solicitud posterior, deberá almacenarla en algún lugar. Django proporciona varias maneras para archivar esto:

1) Se puede utilizar sessions para almacenar la consulta: Cada visitante que visita su sitio conseguirá un objeto sesión vacía y se puede almacenar lo que quieras dentro de este objeto, que actúa como un dict Drawback: un solo visitante no puede hacer múltiples búsquedas con paginación al mismo tiempo.

2) Use cookies: Si configura una cookie que está almacenada en el lado del cliente, el navegador agregará los datos de la cookie a cada solicitud en la que pueda acceder a ella. Las cookies son más amigables para el servidor, ya que no necesita un administrador de sesión para ellas en el servidor, pero los datos almacenados en las cookies son visibles (y editables) para el cliente. Drawback: lo mismo que antes.

3) Use los campos ocultos: Puede agregar un formulario con algunos campos ocultos en su página de resultados de búsqueda y almacenar la consulta dentro de ellos. Luego, el cliente reenviará la consulta cada vez que envíe el formulario. Drawback: debe usar un formulario con botones de envío para la paginación en su página (los enlaces simples no funcionarán).

4) Crear enlaces que contienen la consulta: En lugar de utilizar POST, también puede utilizar GET. Por ejemplo, podría tener un enlace como "/search/hello+world/?order=votes" y "enlaces paginados" como "/search/hello+world/2/?order-votes". Luego, la consulta se puede recuperar fácilmente desde la URL. Drawback: la cantidad máxima de datos que puede enviar a través de GET es limitada (pero eso no debería ser un problema para una búsqueda simple).

5) Utilice una combinación: Es posible que desee almacenar todos los datos en una sesión o una base de datos y acceder a ellos a través de una clave generada que puede colocar en la URL. Las URL pueden parecerse al "/search/029af239ccd23/2" (para la 2ª página) y puede usar la clave para acceder a una gran cantidad de datos que ha almacenado anteriormente. Esto elimina el inconveniente de la solución 1 y de la solución 4. Nueva desventaja: mucho trabajo :)

6) utilizar AJAX: con el Ajax puede almacenar los datos en el interior de algunos js-variables en el lado del cliente, que luego se pasaron a las otras peticiones Y como Ajax sólo se actualizará su lista de resultados. , las variables no se pierden.

+0

Gracias, esto es útil. Solo para desempaquetar esta pregunta un poco más: ¿es este el uso previsto para la clase de paginador? Mi vista procesa el formulario de búsqueda inicial, luego envía la plantilla al objeto paginator.page() para la primera página. La lista de resultados se genera desde object_list para esa página. Parece extraño que no pude enviar el conjunto completo de resultados de búsqueda, y de alguna manera navegar a través de él sin volver a enviar la búsqueda de cada página. Si ese es el uso previsto para la clase, puedo trabajar con eso. Solo quiero asegurarme de no perderme algo obvio. ¡Gracias! – andyashton

+1

Sí, ese es el uso previsto. No olvide que Django es un marco web y, por su naturaleza, las solicitudes web no son explícitas. Entonces, si quieres mantener el estado, tendrás que guardarlo en alguna parte, y tux21b te ha dado algunas opciones sobre dónde. –

+0

Muy útil, gracias a los dos. – andyashton

0

Puede solicitar el objeto de solicitud si es ajax, simplemente request.is_ajax. De esta forma puede detectar, ya sea la primera solicitud posterior o más preguntas sobre las páginas siguientes.

0

Haga que el formulario de búsqueda y los resultados se muestren en una sola plantilla django. Inicialmente, use css para ocultar el área de visualización de resultados. Al realizar la publicación, puede verificar si el la búsqueda devolvió cualquier resultado y hola del formulario de búsqueda con css si existen resultados. Si los resultados no existen, use css para ocultar el área de visualización de resultados como antes.En sus enlaces de paginación, use javascript para enviar el formulario, esto podría ser tan simple como document.forms[0].submit(); return false;

Deberá manejar cómo pasar el número de página al motor de búsqueda de django.

4

Leyendo la muy buena respuesta de tux21b Decidí implementar la primera opción, es decir, usar la sesión para almacenar la consulta. Esta es una aplicación que busca bases de datos inmobiliarias. Aquí está el código de la vista (usando Django 1.5):

def main_search(request): 
    search_form = UserSearchForm() 
    return render(request, 'search/busca_inicial.html', {'search_form': search_form}) 


def result(request): 
    if request.method == 'POST': 
     search_form = UserSearchForm(request.POST) 
     if search_form.is_valid(): 
      # Loads the values entered by the user on the form. The first and the second 
      # are MultiChoiceFields. The third and fourth are Integer fields 
      location_query_list = search_form.cleaned_data['location'] 
      realty_type_query_list = search_form.cleaned_data['realty_type'] 
      price_min = search_form.cleaned_data['price_min'] 
      price_max = search_form.cleaned_data['price_max'] 
      # Those ifs here populate the fields with convenient values if the user 
      # left them blank. Basically the idea is to populate them with values 
      # that correspond to the broadest search possible. 
      if location_query_list == []: 
       location_query_list = [l for l in range(483)] 
      if realty_type_query_list == []: 
       realty_type_query_list = [r for r in range(20)] 
      if price_min == None: 
       price_min = 0 
      if price_max == None: 
       price_max = 100000000 
      # Saving the search parameters on the session 
      request.session['location_query_list'] = location_query_list 
      request.session['price_min'] = price_min 
      request.session['price_max'] = price_max 
      request.session['realty_type_query_lyst'] = realty_type_query_list 
    # making a query outside the if method == POST. This logic makes the pagination  possible. 
    # If the user has made a new search, the session values would be updated. If not, 
    # the session values will be from the former search. Of course, that is what we want because 
    # we want the 'next' and 'previous' pages correspond to the original search 
    realty_list_result = FctRealtyOffer.objects.filter(location__in=request.session['location_query_list'] 
                ).filter(price__range=(request.session['price_min'], request.session['price_max']) 
                ).filter(realty_type__in=request.session['realty_type_query_lyst']) 
    # Here we pass the list to a table created using django-tables2 that handles sorting 
    # and pagination for us 
    table = FctRealtyOfferTable(realty_list_result) 
    # django-tables2 pagination configuration 
    RequestConfig(request, paginate={'per_page': 10}).configure(table) 

    return render(request, 'search/search_result.html', {'realty_list_size': len(realty_list_result), 
                 'table': table}) 

creo que sirve Si alguien tiene alguna mejora para sugerir, será bienvenida!.

4

Como @rvnovaes, una forma de utilizar la sesión para resolver el problema. El inconveniente de su solución es que si hay muchos campos de búsqueda, debe escribir muchas líneas de código, y también si muestra el formulario de búsqueda en la página de resultados, todos los campos estarán en blanco, mientras que deberían mantenerse en blanco. sus valores

Así que prefiero guardar todos los datos de correos en sesión, y al comienzo de la vista forzar el valor de request.POST y request.method si una sesión se define:

""" ... """ 
if not request.method == 'POST': 
    if 'search-persons-post' in request.session: 
     request.POST = request.session['search-persons-post'] 
     request.method = 'POST' 

if request.method == 'POST': 
    form = PersonForm(request.POST) 
    request.session['search-persons-post'] = request.POST 
    if form.is_valid(): 
     id = form.cleaned_data['id'] 
""" ... """ 

Más información here