javascript - 如何在 Django 应用程序中使用 Ajax 搜索时对类型进行分页
问题描述
当您在带有分页的 Django 应用程序中使用 ajax 搜索时,我正在实现一种类型。我希望在用户在数据库中键入他们的搜索词而不是带有提交按钮的表单时刷新结果。我正在使用 Django 的内置分页对数据进行分页并将其显示在模板中。
马上:
- HTTP GET 参数在 Django 视图中处理,并使我们的视图捕获用户的查询。
- Django 视图处理 Ajax 请求并使用包含新(模板)结果的 JSON 响应正确响应它们。
- 一旦用户开始在 HTML 搜索框中输入内容,JavaScript 和 jQuery 就会向我们的视图发送一个 Ajax 请求。
- 此请求将包含术语,以便服务器可以返回相关结果。
- 一旦我们的视图返回 JSON 响应,我们的 JS 代码将使用它来更改呈现给用户的信息,而无需刷新页面。
问题:
目前,当我收到我的搜索结果并转到第二页时,我收到了与我认为丢失的搜索查询无关的结果。例如搜索“约翰”,我有一个以“约翰”为名称的对象(艺术家姓名)列表。当我因为有很多约翰的页面而按下一页时,我丢失了这个“约翰”查询,它显示了我所有艺术家列表的第二页,而忽略了我的搜索参数约翰。
有没有办法对我的结果进行分页,而不会在我更改页面时重新加载(动态加载)并丢失我的 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"),
]
'''
解决方案
您可以为此任务使用自定义模板标签,这些是接受或不接受参数并返回结果的简单函数,您将能够将它们加载到模板中并将它们用作任何其他内置 Django 模板,您可以创建一个模板标签,该标签可以通过为您的请求传递必要的参数来自动构造一个 url。
您可以在以下链接中阅读更多内容:在此处输入链接描述
对于此任务,您需要三样东西:
- 您请求的查询本身
- 您请求此信息的路径
- 您请求的页码
为了简单起见,每次我们通过 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 %}"
建议
- 我建议为此任务使用部分模板,这样您就无需使用更新的数据作为页码再次删除和添加模板。
推荐阅读
- php - 为什么 session_commit() 会导致'允许的 268435456 字节的内存大小已用完'
- asp.net-mvc - 使用深色主题时,Visual Studio 2017 弹出窗口具有透明文本
- javascript - AJAX - 数据对象的 URL
- protractor - 量角器 ExpectedConditions 等待 DOM 属性包含
- firebase - 使用 Facebook 进行身份验证时,如何防止登录 facebook.com
- reactjs - 如何在本机反应中获取 TextInput 更改事件的目标?
- vba - 用于取消组合文本框的 Word 宏
- azure - 添加机密时拒绝访问
- sql - 从 HP QC 数据库的 Root 开始获取文件夹完整路径的 SQL 查询
- mfc - 函数“隐藏”和 OnSize