2010-02-15 2 views
17

Я использую Django Forms для выполнения фильтрации/фасетированного поиска через POST, и я бы хотел, чтобы класс panginator Django организовал результаты. Как сохранить исходный запрос при передаче клиента между различными страницами? Другими словами, кажется, что я теряю данные POST, как только передаю запрос GET для другой страницы обратно к моим представлениям. Я видел некоторые рекомендации по использованию AJAX для обновления только блока результатов страницы, но мне интересно, есть ли для этого механизм Django.Разбиение на страницы результатов Django POST-запроса

Спасибо.

ответ

23

Если вы хотите получить доступ к данным хранилища в более позднем запросе, вам придется его где-то хранить. Django предоставляет несколько способов архивировать это:

1) Вы можете использовать sessions для хранения запроса: Каждый посетитель, который посещает ваш сайт будет получать объект сеанса, и вы можете хранить все, что вы хотите внутри этого объекта, который действует как дикт. Недостаток: один посетитель не может выполнять множественный поиск с разбивкой по страницам одновременно.

2) Использование файлов cookie: Если вы установили cookie, который хранится на стороне клиента, браузер добавит данные cookie к каждому запросу, к которому вы можете получить доступ. Файлы cookie более дружественны к серверу, потому что для них на сервере не нужен диспетчер сеансов, но данные, хранящиеся в файлах cookie, видны (и редактируются) клиенту. Недостаток: тот же, что и раньше.

3) Использование скрытых полей: Вы можете добавить форму с некоторыми скрытыми полями на страницу результатов поиска и сохранить запрос внутри них. Затем клиент отправляет запрос при отправке формы. Недостаток: вы должны использовать форму с кнопками отправки для разбивки на страницы на странице (простые ссылки не будут работать).

4) Создать ссылки, содержащие запрос: Вместо использования POST вы также можете использовать GET. Например, у вас может быть ссылка вроде "/search/hello+world/?order=votes" и «с разбивкой на страницы», например, "/search/hello+world/2/?order-votes". Затем запрос можно легко получить из URL-адреса. Недостаток: максимальный объем данных, которые вы можете отправлять через GET, ограничен (но это не должно быть проблемой для простого поиска).

5) Используйте комбинацию: Возможно, вы захотите сохранить все данные в сеансе или базе данных и получить к ним доступ с помощью сгенерированного ключа, который вы можете поместить в URL-адрес. URL-адреса могут выглядеть так: «/search/029af239ccd23/2" (для 2-й страницы), и вы можете использовать ключ для доступа к огромному количеству данных, которые вы сохранили ранее. Это устраняет недостаток решения 1, а также решение 4. Новый недостаток: много работы :)

6) Использование AJAX: с помощью AJAX вы можете хранить данные в некоторых JS-переменных на стороне клиента, который может затем пропускают к другим запросам И поскольку AJAX будет обновлять только свой список. , переменные не теряются.

+0

Спасибо, это полезно. Просто, чтобы распаковать этот вопрос еще немного: это предназначение для класса paginator? Мой просмотр обрабатывает начальную форму поиска, а затем отправляет шаблон объекту paginator.page() для первой страницы. Список результатов генерируется из object_list для этой страницы. Кажется странным, что я не мог отправить его весь набор результатов поиска, и каким-то образом прокручивать его, не перегружая поиск для каждой страницы. Если это предназначение для класса, я могу работать с ним. Просто хочу убедиться, что я не пропущу что-то очевидное. Благодаря! – andyashton

+1

Да, это предполагаемое использование. Не забывайте, что Django - это веб-инфраструктура, и по своей природе веб-запросы несовместимы. Поэтому, если вы хотите сохранить состояние, вам придется его где-то хранить - и tux21b предоставил вам некоторые варианты относительно того, где. –

+0

Очень полезно, спасибо вам обоим. – andyashton

0

Вы можете запросить объект запроса, если он ajax, просто request.is_ajax. Таким образом, вы можете определить, является ли это первым почтовым запросом или дополнительными вопросами о следующих страницах.

0

Имейте форму поиска и результаты на одном шаблоне django. Сначала используйте css, чтобы скрыть область отображения результатов. При отправке формы вы можете проверить, поиск дал какие-либо результаты и привет в форме поиска с помощью css, если результаты существуют. Если результатов не существует, используйте css, чтобы скрыть область отображения результатов, как раньше.В ваших ссылках на страницы используйте javascript для отправки формы, это может быть так же просто, как document.forms[0].submit(); return false;

Вам нужно будет обработать, как передать номер страницы движку поискового вызова django.

4

Чтение очень приятного ответа от tux21b Я решил реализовать первый вариант, т. Е. Использовать сеанс для хранения запроса. Это приложение, которое ищет базы данных недвижимости. Вот код, вид (с использованием 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}) 

Надеется, что это помогает, если у кого есть какое-либо улучшение, чтобы предложить, то добро пожаловать!.

4

Как @rvnovaes, способ использовать сеанс для решения вопроса.

Недостатком его решения является то, что если есть много полей поиска, вы должны написать много строк кода, а также, если вы покажете форму поиска на странице результатов, все поля будут пустыми, в то время как они должны содержать их значения.

Так что я предпочел бы сохранить все почтовые данные в сессии, а в начале зрения заставить значение request.POST и request.method если сеанс определяется:

""" ... """ 
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'] 
""" ... """ 

Подробнее here