首页 > 解决方案 > 如何在 Django 应用程序中使用 Ajax 搜索时对类型进行分页

问题描述

当您在带有分页的 Django 应用程序中使用 ajax 搜索时,我正在实现一种类型。我希望在用户在数据库中键入他们的搜索词而不是带有提交按钮的表单时刷新结果。我正在使用 Django 的内置分页对数据进行分页并将其显示在模板中。

马上:

问题:

目前,当我收到我的搜索结果并转到第二页时,我收到了与我认为丢失的搜索查询无关的结果。例如搜索“约翰”,我有一个以“约翰”为名称的对象(艺术家姓名)列表。当我因为有很多约翰的页面而按下一页时,我丢失了这个“约翰”查询,它显示了我所有艺术家列表的第二页,而忽略了我的搜索参数约翰。

有没有办法对我的结果进行分页,而不会在我更改页面时重新加载(动态加载)并丢失我的 URL 查询“John”?

(js.html 文件有指向 Artist.js 文件的链接,并通过 CDN 托管 jquery)

视图.py

'''

from django.template.loader import render_to_string
from django.http import JsonResponse

def artist_list(request):
    url_parameter = request.GET.get('q')

    if url_parameter:
        artists = Pagination(request, Artist.objects.filter(name__icontains=url_parameter)
    else:
        artists = Pagination(request, Artist.objects.all()

    if request.is_ajax():
        html = render_to_string(
        template_name='artist_replaceable_content.html', context={'artists': artists}
    )
        
        data_dict = {'html_from_view': html}
        return JsonResponse(data=data_dict, safe=False)

    return render(request, 'artist.html', context={'artists': artists})

'''

艺术家.html

'''

   {% load static %}
   {% load crispy_forms_tags %}
   {% block content %}
   {% include "css.html" %}
    <div class="container-fluid bg-soft">
     <main class="content">                                               
      <h2 class="h4">Artist_List</h2>                         
       <div class="input-group">
        <div class="input-group-prepend"><span class="input-group-text"><span class="fas fa-search" id="search-icon"></span></span>
        </div>                         
           <input class="form-control" id="searchInput" name='Search' placeholder="Search" type="text" aria-label="user search">
        </div>                        
      <div class="border bg-white" id="replaceable-content">
       {% include 'artist_replaceable_content.html' %}

    </div>
    </main>
  </div>
  {% include "js.html" %}
  {% endblock %}

'''

艺术家可替换内容.html

'''

{% load static %}

{% if artists %}
    {% for artist in artists %}
       <div class="card hover-state">
       <h3 class="h5">{{ artists.title }}</h3>
       </div>
    {% endfor %}
    {% else %}
      <span class="font-weight-normal text-gray">No artists found!</span>
{% endif %}
         <div class="card-footer">
         <nav aria-label="Page navigation example">
         <ul class="pagination">
         {% if artists.has_other_pages %}
             {% if artists.has_previous %}
               <li class="page-item"><a class="page-link" href="page=1">First</a></li>
               <li class="page-item"><a class="page-link" href="?page={{ artists.previous_page_number }}">Previous</a></li>
             {% endif %}                                 
             {% for i in artists.paginator.page_range %}
                {% if artists.number == i %}
                   <li class="page-item active"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
                {% elif i > artists.number|add:'-5' and i < artists.number|add:'5' %}
                   <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }} </a></li>
                {% endif %}
             {% endfor %}
             {% if artists.has_next %}
                <li class="page-item"><a class="page-link" href="?page={{ artists.next_page_number }}">Next</a></li>
             {% endif %}
         {% endif %}
      </ul>
      </nav>
      <div class="font-weight-bold small">Showing<b>{{ artists.start_index {{artists.end_index }}</b> out of <b>{{ artists.paginator.count }}</b> entries</div>
      </div>

'''

艺术家.js:

'''

 $(document).ready(function() {
 const search_Input = $("#searchInput")
 const artists_content = $('#replaceable-content')
 const search_icon = $('#search-icon')

 const endpoint = '/artists/'
 const delay_by_in_ms = 700
 let scheduled_function = false

 // getJSON() method to send an Ajax request to the endpoint alongside the parameters.
 let ajax_call = function (endpoint, request_parameters) {
   $.getJSON(endpoint, request_parameters)
      .done(response => {
          // fade out artists_content, replace and fade in artists_content
          artists_content.fadeTo('fast', 0).promise().then(() => {
          artists_content.html(response['html_from_view'])
          artists_content.fadeTo('fast', 1)     
          })
      })
 }
 // start
 search_Input.on('keyup', function () {
         event.preventDefault();

     const request_parameters = {
         q: $(this).val() // value of user_input: the HTML element with ID user-input
     }

     // if scheduled_function is NOT false, cancel the execution of the function
     if (scheduled_function) {
         clearTimeout(scheduled_function)
     }
     // setTimeout returns the ID of the function to be executed
     scheduled_function = setTimeout(ajax_call, delay_by_in_ms, endpoint, request_parameters)
     })
});

''' urls.py

'''

 from django.urls import path
 from core import views as core_views

 urlpatterns = [

     path("artists/", core_views.artists_view, name="artists"),
 ]

'''

标签: javascriptjquerydjangoajaxpagination

解决方案


您可以为此任务使用自定义模板标签,这些是接受或不接受参数并返回结果的简单函数,您将能够将它们加载到模板中并将它们用作任何其他内置 Django 模板,您可以创建一个模板标签,该标签可以通过为您的请求传递必要的参数来自动构造一个 url。

您可以在以下链接中阅读更多内容:在此处输入链接描述

对于此任务,您需要三样东西:

  1. 您请求的查询本身
  2. 您请求此信息的路径
  3. 您请求的页码

为了简单起见,每次我们通过 AJAX 请求查询时,服务器都会将相同的查询返回给前端,如下所示:

视图.py 文件

from django.template.loader import render_to_string
from django.http import JsonResponse

def artist_list(request):
    url_parameter = request.GET.get('q')

    if url_parameter:
        artists = Pagination(request, Artist.objects.filter(name__icontains=url_parameter)
    else:
        artists = Pagination(request, Artist.objects.all()

    if request.is_ajax():
        html = render_to_string(
        template_name='artist_replaceable_content.html', context={'artists': artists, 'url_parameter': url_parameter}
    )
        
        data_dict = {'html_from_view': html}
        return JsonResponse(data=data_dict, safe=False)

    return render(request, 'artist.html', context={'artists': artists})

请查看我们随每个 AJAX 请求响应返回的上下文(上下文)

现在是时候构建我们​​的自定义模板标签了:

要创建我们的自定义模板标签,我们需要在我们的 app 文件夹中创建一个 templatetags 文件夹,在这个 templatetags 文件夹中,我们添加相应的init .py 文件以允许 Python 将此文件夹视为一个包,以及一个具有任何名称的 .py 文件你想要的,例如:custom_tags.py

由内而外 custom_tags.py 文件

from django import template

register = template.Library()

@register.simple_tag
def get_query(url, query, page):
    """
        DOCSTRING: The get_query custom template tag will construct a URL for further use in pagination based
                    on the parameters received.
    """
    return url + '?query=' + query + '&page=' + page

请注意,您需要重新启动服务器才能注册模板标签。

下一步是将它们加载到您的模板中,如下所示:

{% load static %}

<!-- Loading Custom Tags -->
{% load custom_tags %}

{% if artists %}
    {% for artist in artists %}
       <div class="card hover-state">
       <h3 class="h5">{{ artists.title }}</h3>
       </div>
    {% endfor %}
    {% else %}
      <span class="font-weight-normal text-gray">No artists found!</span>
{% endif %}
         <div class="card-footer">
         <nav aria-label="Page navigation example">
         <ul class="pagination">
         {% if artists.has_other_pages %}
             {% if artists.has_previous %}
               <li class="page-item"><a class="page-link" href="page=1">First</a></li>
               <li class="page-item"><a class="page-link" href="?page={{ artists.previous_page_number }}">Previous</a></li>
             {% endif %}                                 
             {% for i in artists.paginator.page_range %}
                {% if artists.number == i %}
                   <li class="page-item active"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
                {% elif i > artists.number|add:'-5' and i < artists.number|add:'5' %}
                   <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }} </a></li>
                {% endif %}
             {% endfor %}
             {% if artists.has_next %}
                <li class="page-item"><a class="page-link" href="?page={{ artists.next_page_number }}">Next</a></li>
             {% endif %}
         {% endif %}
      </ul>
      </nav>
      <div class="font-weight-bold small">Showing<b>{{ artists.start_index {{artists.end_index }}</b> out of <b>{{ artists.paginator.count }}</b> entries</div>
      </div>

使用模板标签

<li class="page-item"><a class="page-link" href="{% get_query url url_parameter artists.next_page_number %}"

建议

  1. 我建议为此任务使用部分模板,这样您就无需使用更新的数据作为页码再次删除和添加模板。

推荐阅读