对过滤器进行分页

Paginate a filter

我有一个过滤器,其中包含汽车品牌和型号的相关下拉列表。因为我不想在一页上显示所有这些,所以我添加了一个分页器。问题是过滤器工作正常,但它不会在页面中延续

当过滤器处于活动状态时,url 看起来像

/cars/?manufacture=2&model=2 如果我转到下一页,我得到的只是 /cars/?page=2

我想要 /cars/?manufacture=2&model=2?page=2

如果我打印 {{ posts|length }},它会 return 正确数量的项目被过滤,所以那里没有问题

我认为问题出在模板中的下一个和上一个按钮上,因为除了下一页之外,它们没有在其中传递任何参数。如何将过滤器带入分页器。

查看

def allCarsView(request):

    model = Post
    
    myFilter = carFilter(request.GET, queryset=Post.objects.all())
    posts = myFilter.qs
    
    page = request.GET.get('page', 1)
    paginator = Paginator(posts.order_by('date_posted'), 2)
    page_obj = paginator.get_page(page)
    page_range = paginator.get_elided_page_range(number=page)
    
    context = {
        'posts':posts, 'myFilter':myFilter, 'page_range': page_range, 
        'page': page, 'paginator': paginator, 'page_obj': page_obj
    }
    return render(request, 'blog/cars.html', context)    

分页器html

<nav aria-label="Page navigation example " class="paginator">
<nav aria-label="Page navigation example " class="paginator">
    <ul class="pagination justify-content-center">
        <li class="page-item">
            {% if page_obj.has_previous %}
            <a class="page-link" href="?page={{ page_obj.previous_page_number }}" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
            {% else %}
        </li>

        <li class="page-item disabled">
            <a class="page-link" href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        {% endif %} {% for i in page_obj.paginator.page_range %} {% if page_obj.number == i %}
        <li class="page-item active" aria-current="page">
            <a class="page-link" href="#">{{ i }}</a>
        </li>
        {% elif i > page_obj.number|add:'-3' and i < page_obj.number|add:'3' %}
        <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
        {% endif %} {% endfor %}

        <li class="page-item">
            {% if page_obj.has_next %}
            <a class="page-link" href="?page={{ page_obj.next_page_number }}" aria-label="Previous">
                <span aria-hidden="true">&raquo;</span>
            </a>
            {% else %}
        </li>

        <li class="page-item disabled">
            <a class="page-link" href="#" aria-label="Previous">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
        {% endif %}
    </ul>
</nav>

更新: 通过更多的研究,我的问题似乎是分页器中的 urls,因为它们不携带任何参数。似乎没有最好的方法来做到这一点,我尝试过的解决方案没有产生任何效果。

更新: 正在尝试使用此 post as the solution

查看(在之前的代码下添加) 从 django 导入模板 注册 = template.Library()

@register.simple_tag
def url_replace(request, field, value):

    dict_ = request.GET.copy()

    dict_[field] = value

    return dict_.urlencode()

模板:

<a class="page-link" href="?{% url_replace request 'page' page_obj.next_page_number %}" aria-label="Previous">

然后我得到错误

Invalid block tag on line 88: 'url_replace', expected 'elif', 'else' or 'endif'. Did you forget to register or load this tag?

所以在顶部,如果我添加

{% load url_replace %}

抛出错误

'url_replace' is not a registered tag library

尝试能够 select 来自分页器的页码

            {% elif i > page_obj.number|add:'-3' and i < page_obj.number|add:'3' %}
            {% if page_obj.number > i  %}
                <li class="page-item"><a class="page-link" href="?{% querystring_replace request 'page' page_obj.previous_page_number %}">{{ i }}</a></li>    
            {% endif %}
            {% if page_obj.number < i  %}
                <li class="page-item"><a class="page-link" href="?{% querystring_replace request 'page' page_obj.next_page_number %}">{{ i }}</a></li>    
            {% endif %}
        {% endif %} {% endfor %}

每个网络请求都是独立的。服务器不记得您之前发送的内容。因此客户端(浏览器)应该保持(记住)当前上下文并提出适当的请求。

在下面的代码中,您没有传递任何过滤器参数。

<a class="page-link" href="?page={{ page_obj.next_page_number }}"/>

以上代码实际呈现如下

<a class="page-link" href="?page=3"/>

要分页和过滤,您应该传递过滤参数。正确的 HTML 应该如下所示。查询字符串比以前多了。

<a class="page-link" href="?page=3&FILTER_A=FOO&FILTER_B=BAR"/>

有几种方法可以实现基于先前请求的查询字符串附加额外的查询字符串。

  • 服务器端

    1. 模板标签
    2. 纯 Django 模板

    已有相同的问答。并且通过 1&2 方式有很多答案。

    How to paginate Django with other get variables?

    1. 第三方

    https://django-tables2.readthedocs.io/en/latest/#

    Django-tables 是渲染 table 的不错选择。这个包有自己的分页器模板(HTML)和模板标签和其他代码。如果您选择使用它,下面的代码可能有助于同时使用过滤器和具有内置分页器的 table。

    class BaseFilteredTableView(SingleTableView):
        ...
        def get_queryset(self, **kwargs):
            qs = super().get_queryset(**kwargs)

            filter = BarFilter(self.request.GET, queryset=qs, **kwargs)
            return filter.qs
  • 客户端

    1. 来自 JavaScript
//javascript
<script>
    console.log(window.location.href)
</script>

window.location.href 将 return 查询字符串。你可以解析它并将查询字符串附加到每个分页器 a-link

这可以使用 this answer 中所示的自定义模板标签来完成。但是,该答案跳过了创建自定义标签的整个过程,所以让我向您展示如何操作。

Django 要求您的自定义标签保存在应用程序内名为 templatetags 的文件夹中。所以这就是您的应用程序的文件夹结构必须如下所示:

my-app/
├─ __ini__.py
├─ models.py
├─ views.py
├─ templatetags/
│  ├─ __init__.py
│  ├─ myapp_tags.py

提示:您还可以创建一个专门用于保留自定义标签的新应用。这样就很容易在不同的项目中重复使用它们。确保您的新应用在 INSTALLED_APPS 列表中。

现在打开 myapp_tags.py 文件并在其中创建自定义标签:

# myapp_tags.py

from django import template

register = template.Library()

@register.simple_tag
def querystring_replace(request, key, value):
    """Replace the given `key` with the given `value`
    in the request's querystring. The rest of the
    querystring remains unchanged.
    """
    query_dict = request.GET.copy()
    query_dict[key] = value
    return query_dict.urlencode()

要在模板中使用此标签,您需要加载包含标签的文件

 <!-- load the file containing the tags -->
{% load myapp_tags %}

<!-- now you can use all the tags from myapp_tags -->
{% querystring_replace request 'page' page_obj.next_page_number %}