Разбиение результатов POST-запросов на формы Django - PullRequest
18 голосов
/ 15 февраля 2010

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

Спасибо.

Ответы [ 7 ]

25 голосов
/ 15 февраля 2010

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

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

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

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. Новое недостаток: много работы :) 1026 *

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

6 голосов
/ 07 августа 2013

Читая очень хороший ответ от 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})

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

5 голосов
/ 19 сентября 2014

Как @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']
""" ... """

Подробнее здесь

0 голосов
/ 10 мая 2019

Мое предложение было бы сохранить запрос на публикацию с использованием сеанса или файла cookie. В случае, если данные поста являются конфиденциальными, вы должны использовать сеанс для их хранения. Приведенный ниже код содержит мою логику для реализации его с помощью сеанса.

def index(request):
    is_cookie_set = 0
    # Check if the session has already been created. If created, get their values and store it.
    if 'age' in request.session and 'sex' in request.session: 
        age = request.session['age']
        sex = request.session['sex']
        is_cookie_set = 1
    else:
        # Store the data in the session object which can be used later
        request.session['age'] = age
        request.session['sex'] = sex
    if(request.method == 'POST'):
        if(is_cookie_set == 0): # form submission by the user
            form = EmployeeForm(request.POST)
            sex = form.cleaned_data['sex']
            age = form.cleaned_data['age']
            if form.is_valid():
                result = Employee.objects.all(sex=sex,age_gte=age) # filter all employees based on sex and age
        else: # When the session has been created
            result = Employee.objects.all(sex=sex,age_gte=age)
        paginator = Paginator(result, 20) # Show 20 results per page
        page = request.GET.get('page')
        r = paginator.get_page(page)
        response = render(request, 'app/result.html',{'result':result})    
        return response
    else:
        form = EmployeeForm()
    return render(request,'app/home.html',{'form':form})

Вам также следует проверить, не заполнены ли поля сообщений, и изменить логику в соответствии с этим. Вы также можете сохранить весь почтовый запрос в сеансе, как предложено @abidibo.

Вы также можете использовать куки для того же. Я объяснил это здесь

0 голосов
/ 09 сентября 2018

Я сделал это в своем веб-приложении с параметрами get. Может быть, я могу вам помочь:

Views.py

class HomeView(ListView):
model = Hotel
template_name = 'index.html'
paginate_by = 10  # if pagination is desired

def get_queryset(self):
   qs = super().get_queryset()
   kwargs = {}
   if 'title' in self.request.GET:
       title = self.request.GET.get('title')
       if title != '':
           kwargs['title__icontains'] = title
   if 'category' in self.request.GET:
       category = self.request.GET.get('category')
       if category:
           kwargs['category_id'] = category
   if 'size' in self.request.GET:
       size = self.request.GET.get('size')
       if size:
           kwargs['size_id'] = size
   if 'service' in self.request.GET:
       service = self.request.GET.get('service')
       if service:
           kwargs['service_id'] = service
   if 'ownership' in self.request.GET:
       ownership = self.request.GET.get('ownership')
       if ownership:
           kwargs['ownership_id'] = ownership
   qs = qs.filter(**kwargs)
   return qs

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    form_init = {}
    form = SearchForm()
    if self.request.GET.items():
        try:
            parameters = self.request.GET.items()
        except KeyError:
            parameters = {}
        for key, value in parameters:
            for field in form.fields:
                if key == field:
                    form_init[key] = value
        form.initial = form_init
    if 'title' in self.request.GET:
       title = self.request.GET.get('title')
       if title != '':
           context.update({
            'title': title
           })
    if 'category' in self.request.GET:
       category = self.request.GET.get('category')
       context.update({
        'category': category
       })
    if 'size' in self.request.GET:
       size = self.request.GET.get('size')
       context.update({
           'size': size
      })
    if 'service' in self.request.GET:
       service = self.request.GET.get('service')
       context.update({
           'service': service
      })
    if 'ownership' in self.request.GET:
       ownership = self.request.GET.get('ownership')
       context.update({
          'ownership': ownership
       })
    context.update({
        'search_form': form
    })
    return context

Файл пагинации html

<div class="row">
  {% if is_paginated %}
  <nav aria-label="...">
    <ul class="pagination">
      {% if page_obj.has_previous %}
        <li class="page-item"><a class="page-link" href="?category={{category}}&size={{size}}&service={{service}}&ownership={{ownership}}&page={{ page_obj.previous_page_number }}">Previous</a></li>
      {% else %}
        <li class="page-item disabled"><span class="page-link">Previous</span></li>
      {% endif %}
      <span class="page-current">
               Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
           </span>
      {% if page_obj.has_next %}
        <li class="page-item"><a class="page-link" href="?category={{category}}&size={{size}}&service={{service}}&ownership={{ownership}}&page={{ page_obj.next_page_number }}">Next</a></li>
      {% else %}
        <li class="page-item disabled"><span class="page-link">Next</span></li>
      {% endif %}
    </ul>
  </nav>
 {% endif %}
</div>
0 голосов
/ 03 июля 2010

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

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

0 голосов
/ 15 февраля 2010

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

...