Django分页查询的前后链接

4 投票
5 回答
7824 浏览
提问于 2025-04-18 00:27

我正在为Django制作一个搜索表单。

这个搜索表单很普通,搜索后会返回一个匹配的表格。我希望能对返回的表格进行分页。

问题出在“上一页”和“下一页”按钮上。返回查询的链接是 /records/search/?query=a(搜索示例是 a)。页面会输出表格和它的上一页、下一页链接。但是这些链接重定向到 /records/search/?page=2,结果页面显示的是一个空白的表格。

谁能帮我看看,上一页和下一页的链接应该怎么设置?

search.html:

{% extends 'blank.html' %}

{% block content %}

    <div class="row">
    <form id="search-form" method="get" action=".">
      {{ form.as_p }}
      <input type="submit" value="Search" />
    </form>
    </div>
    <br><br>

//display table code//

{% if is_paginated %}
<div class="pagination">
    <span class="step-links">
        {% if agent_list.has_previous %}
            <a href="?page={{ agent_list.previous_page_number }}{% for key,value in request.GET.items %}{% ifnotequal key 'page' %}&{{ key }}={{ value }}{% endifnotequal %}{% endfor %}">forrige</a>
        {% endif %}

        <span class="current">
            Page {{ agent_list.number }} of {{ agent_list.paginator.num_pages }}.
        </span>

        {% if agent_list.has_next %}
            <a href="?page={{ agent_list.next_page_number }}">Next</a>
        {% endif %}
    </span>
</div>
{% endif %}

{% endblock %}

还有搜索视图:

def search_page(request):
    form = SearchForm()
    agents = []
    show_results=False

    if request.GET.has_key('query'):
        show_results=True
        query=request.GET['query'].strip()
        if query:
            form=SearchForm({'query': query})
            agents = \
                Agent.objects.filter(Q(name__icontains=query))


    paginator = Paginator(agents, 10)
    page = request.GET.get('page')
    try:
        agents = paginator.page(page)
    except PageNotAnInteger:
        agents = paginator.page(1)
    except EmptyPage:
        agents = paginator.page(paginator.num_pages)


    variables = RequestContext(request, 
        {   'form': form,
            'agent_list': agents,
            'show_results': show_results,
            'is_paginated': True,
        }
    )

    return render_to_response('search.html', variables)

我见过类似的问题,但我不太明白,也没能让它们工作。谁能帮帮我?


编辑:

为了快速解决这个问题(我还没仔细考虑缺点),

我在我的视图中添加了一个变量:

variables = RequestContext(request, 
    {   'form': form,
        'agent_list': agents,
        'show_results': show_results,
        'is_paginated': True,
        **'query': query,**
    }
)

这里的 query 是接收到的 query 变量,没有引号。

然后简单地把URL改成:

<a href="**?query={{query}}**&page={{ agent_list.previous_page_number }}">Previous</a>

如果你有更好的方法来解决这个问题,欢迎分享,或者在你当前打开的URL后面添加一个链接。

5 个回答

0

你可以这样做,我之所以使用这个,是因为我在网址中直接使用了过滤器,所以所有的网址参数都用来构建下一个或上一个网址。

import re
from django import template

register = template.Library()
PAGE_NUMBER_REGEX = re.compile(r'(page=[0-9]*[\&]*)')   

@register.simple_tag
def append_page_param(value,pageNumber=None):
'''
remove the param "page" using regex and add the one in the pageNumber if there is one
'''
value = re.sub(PAGE_NUMBER_REGEX,'',value) 
if pageNumber:
    if not '?' in value:
        value += f'?page={pageNumber}'
    elif value[-1] != '&':
        value += f'&page={pageNumber}'
    else:
        value += f'page={pageNumber}'
return value

然后,在你的分页导航中,你可以这样调用它:

{% append_page_param request.get_full_path page_obj.previous_page_number %}
1

你可以使用 {{ request.get_full_path }} 这个模板标签。

<a href="{{ request.get_full_path }}&page={{ agent_list.next_page_number }}">下一页</a>

2

下面的内容在提交搜索表单之前和之后都能正常工作:

Views.py

class PostListView(ListView):
    model = Post #.objects.select_related().all()
    template_name = 'erf24/home.html'  # <app>/<model>_<viewtype>.html
    context_object_name = 'posts'      # default >> erf24/post_list.html
    ordering = ['date_posted']
    paginate_by = 3

def is_valid_queryparam(param):
    return param != '' and param is not None
def invalid_queryparam(param):
    return param == '' and param is None

class SearchView(ListView):
    model = Post #.objects.select_related().all()
    template_name = 'erf24/home.html'  # <app>/<model>_<viewtype>.html
    context_object_name = 'posts'      # default >> erf24/post_list.html
    ordering = ['date_posted']
    paginate_by = 3

    def get_queryset(self): # new
        key = self.request.GET.get('key')
        minp = self.request.GET.get('min')
        maxp = self.request.GET.get('max')

        if is_valid_queryparam(key):
            obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct().order_by('date_posted')

        if is_valid_queryparam(minp):
            obj = Post.objects.filter(Q(price__gte=minp)).distinct().order_by('date_posted')
        if is_valid_queryparam(maxp):
            obj = Post.objects.filter(Q(price__lte=maxp)).distinct().order_by('date_posted')

        if is_valid_queryparam(minp) & is_valid_queryparam(maxp):
            obj = Post.objects.filter(Q(price__gte=minp) & Q(price__lte=maxp)).distinct().order_by('date_posted')

        if is_valid_queryparam(key) & is_valid_queryparam(minp) & is_valid_queryparam(maxp):
            obj = Post.objects.filter(Q(content__icontains=key) | Q(location__icontains=key)).distinct()
            obj = obj.filter(Q(price__gte=minp) & Q(price__lte=maxp)).order_by('date_posted')

        if invalid_queryparam(key) & invalid_queryparam(minp) & invalid_queryparam(maxp):
            obj = Post.objects.all()

        return obj

url.py

urlpatterns = [
    path('', PostListView.as_view(), name='erf24-home'),
    path('search/', SearchView.as_view(), name='erf24-search'),
]

Home.html

<form action="{% url 'erf24-search' %}" method="GET">
    <div class="form-group">
        <label for="inputAddress">Search keyword</label>
        <input type="text" class="form-control" id="key" name="key" placeholder="keyword">
    </div>

    <label for="">Price</label>
    <div class="form-row">
        <div class="form-group col-md-6">
            <input type="number" class="form-control" id="min" name="min" placeholder="min price">
        </div>
        <div class="form-group col-md-6">
            <input type="number" class="form-control" id="max" name="max" placeholder="max price">
        </div>
    </div>

    <button type="submit" class="btn btn-primary btn-sm mt-1 mb-1">Search</button>
    <button type="reset" class="btn btn-secondary btn-sm mt-1 mb-1">Clear</button>

</form>

{% for post in posts %}
<article class="media content-section">
    <div class="media-body">
        <div class="article-metadata">
            <img class="rounded-circle article-img" src="{{ post.author.profile.image.url }}" alt="">
            <a href="{% url 'user-posts' post.author.username %}" class="mr-2">{{ post.author }}</a>
            <small class="text-muted">{{ post.date_posted }}</small>
            <!-- use |date: "specs" to filter date display -->
        </div>
        <h2>
            <a href="{% url 'post-detail' post.id %}" class="article-title">{{ post.price }}</a>
        </h2>
        <p class="article-content">{{ post.content }}</p>
        <p class="article-content">{{ post.location }}</p>
        <p><a class="like-btn" data-href="{{ post.get_api_like_url }}" href="">{{ post.likes.count }}
                {% if user in post.likes.all %} Unlike
                {% else %} Like
                {% endif %}
            </a></p>
    </div>
    {% for image in post.image_set.all %}
    <img class="account-img" src="{{ image.image.url }}" alt="">
    {% endfor %}
</article>
{% endfor %}

{% if is_paginated %}
{% if page_obj.has_previous %}
<a href="{% if request.GET.key is not None %}{{ request.get_full_path }}&{% else %}?{% endif %}page=1" class="btn btn-outline-info mb-4">First</a>
<a href="{% if request.GET.key is not None %}{{ request.get_full_path }}&{% else %}?{% endif %}page={{ page_obj.previous_page_number }}" class="btn btn-outline-info mb-4">Previous</a>
{% endif %}

{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a href="{% if request.GET.key is not None %}{{ request.get_full_path }}&{% else %}?{% endif %}page={{ num }}" class="btn btn-info mb-4">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a href="{% if request.GET.key is not None %}{{ request.get_full_path }}&{% else %}?{% endif %}page={{ num }}" class="btn btn-outline-info mb-4">{{ num }}</a>
{% endif %}
{% endfor %}

{% if page_obj.has_next %}
<a href="{% if request.GET.key is not None %}{{ request.get_full_path }}&{% else %}?{% endif %}page={{ page_obj.next_page_number }}" class="btn btn-outline-info mb-4">Next</a>
<a href="{% if request.GET.key is not None %}{{ request.get_full_path }}&{% else %}?{% endif %}page={{ page_obj.paginator.num_pages }}" class="btn btn-outline-info mb-4">Last</a>
{% endif %}
{% endif %}

效果非常好 :) 祝你使用愉快!

3

你可以使用 {{ request.get_full_path }} 这个标签来获取当前的网址。

<a href="{{ request.get_full_path }}&page={{ agent_list.next_page_number }}">Next</a>

这个方法对我有效。

9

我建议把解决方案放在一个模板标签里,像这样:

myapp/templatetags/mytemplatetags.py:

from django import template
register = template.Library()

@register.simple_tag
def url_replace(request, field, value):
    d = request.GET.copy()
    d[field] = value
    return d.urlencode()

@register.simple_tag
def url_delete(request, field):
    d = request.GET.copy()
    del d[field]
    return d.urlencode()

然后在模板中这样使用:

{% load mytemplatetags %}
...
<a href="?{% url_replace request 'page' agent_list.previous_page_number %}">previous</a>

撰写回答