django-filter使用分页

时间:2017-05-18 12:44:58

标签: python django pagination django-filter

我正在使用django-filter包在我的列表视图上提供搜索功能。

现在我想为该视图添加分页。
我正在尝试将分页与过滤的查询集结合起来,但我不知道如何继续。

到目前为止,我已在views.py上尝试了以下内容:

def search(request):
    qs = local_url.objects.filter(global_url__id=1).all()
    paginator = Paginator(qs, 25)
    page = request.GET.get('page')
    try:
        pub = paginator.page(page)
    except PageNotAnInteger:
        pub = paginator.page(1)
    except EmptyPage:
       pub = paginator.page(paginator.num_pages)
    url_filter = PublicationFilter(request.GET, queryset=qs)
    return render(request, 'ingester/search_list.html', {'filter': url_filter, 'publication':pub})

8 个答案:

答案 0 :(得分:5)

这对我有用:

在我的模板中而不是使用此

<li><a href="?page={{ i }}">{{ i }}</a></li>

我写了这个:

{% if 'whatever_parameter_you_use_to_filter' in request.get_full_path %}
   <li><a href="{{ request.get_full_path }}&page={{ i }}"{{ i }}</a></li>
{% else %}
   <li><a href="?page={{ i }}">{{ i }}</a></li>
{% endif %}

我希望它有所帮助:)

答案 1 :(得分:4)

要使用Django Filter并对筛选结果进行分页,您可以执行以下操作:

  1. 为您的模型创建过滤器类:

    my_project/my_app/filters.py

    import django_filters
    
    class MyModelFilter(django_filters.FilterSet):
        class Meta:
            model = MyModel
            # Declare all your model fields by which you will filter
            # your queryset here:
            fields = ['field_1', 'field_2', ...]
    
  2. 每个FilterSet对象都有一个.qs属性,其中包含已过滤的查询集,您甚至可以override it if you want

  3. 我们将对.qs的{​​{1}}属性进行分页:

    MyModelFilter

    my_project/my_app/views.py
  4. 你有它!

    <小时/> PS_1:根据我的经验,Django过滤了"plays" better with Django Rest Framework

    PS_2:如果您要使用DRF,我已经编写了一个示例,说明如何在基于函数的视图中使用分页,您可以轻松地将其与from . import filters def my_view(request): # BTW you do not need .all() after a .filter() # local_url.objects.filter(global_url__id=1) will do filtered_qs = filters.MyModelFilter( request.GET, queryset=MyModel.objects.all() ).qs paginator = Paginator(filtered_qs, YOUR_PAGE_SIZE) page = request.GET.get('page') try: response = paginator.page(page) except PageNotAnInteger: response = paginator.page(1) except EmptyPage: response = paginator.page(paginator.num_pages) return render( request, 'your_template.html', {'response': response} ) 结合使用:

    FilterSet

答案 2 :(得分:2)

此处最重要的部分是如何在模板中构建网址

你可能有

{% if pages.has_previous %}
<li><a href="?page={{ pages.previous_page_number }}">Prev</a></li>
{% endif %}

如果您只使用它来在初始分页结果之间切换,这是完全正常的。

但棘手的部分是当你使用django-fitler过滤器时,查询字符串(&#39;?&#39; 之后的部分)获得全新的键值对,无视您的?page=2或类似内容。

因此,当您单击&#34;下一步&#34;时,要使分页工作与过滤结果一致。或者&#34;上一页&#34;按钮 - 在django-fitler的键值中,您还需要将&page=5作为对传递。

正如@stathoula所提到的,您需要检查查询字符串中是否已存在至少一个过滤字段。如果是,则需要使用已存在的键值对,然后使用新的&page=3对。

看起来很简单,但是当用户点击箭头时,我不得不在查询字符串中一遍又一遍地重复&page=1

在我的情况下,我拥有&#39; title&#39;作为过滤器,所以我需要检查它是否已经存在。

这是我为我的项目完美运作的一小部分。

<强>模板/ pagination.html

<div class="paginator">

    {% with request.get_full_path as querystring %}
        <ul class="pagination nav navbar-nav">

            <!-- Previous page section -->
            {% if pages.has_previous %}
                {% if 'title' in querystring %}
                    {% if 'page' in querystring %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring|slice:":-7" }}&page={{ pages.previous_page_number }}">Prev</a>
                        </li>
                    {% else %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring }}&page={{ pages.previous_page_number }}">Prev</a>
                        </li>
                    {% endif %}
                {% else %}
                    <li class="paginator {% if pages.number == page %}active{% endif %}">
                        <a href="?page={{ pages.previous_page_number }}">Prev</a>
                    </li>
                {% endif %}
            {% endif %}

            <!-- All pages section -->
            {% for page in pages.paginator.page_range %}
                {% if 'title' in querystring %}
                    {% if 'page' in querystring %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring|slice:":-7" }}&page={{ page }}">{{ page }}</a>
                        </li>
                    {% else %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring }}&page={{ page }}">{{ page }}</a>
                        </li>
                    {% endif %}
                {% else %}
                    <li class="paginator {% if pages.number == page %}active{% endif %}">
                        <a href="?page={{ page }}">{{ page }}</a>
                    </li>
                {% endif %}
            {% endfor %}

            <!-- Next page section -->
            {% if pages.has_next %}
                {% if 'title' in querystring %}
                    {% if 'page' in querystring %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring|slice:":-7" }}&page={{ pages.next_page_number }}">Next</a>
                        </li>
                    {% else %}
                        <li class="paginator {% if pages.number == page %}active{% endif %}">
                            <a href="{{ querystring }}&page={{ pages.next_page_number }}">Next</a>
                        </li>
                    {% endif %}
                {% else %}
                    <li class="paginator {% if pages.number == page %}active{% endif %}">
                        <a href="?page={{ pages.next_page_number }}">Next</a>
                    </li>
                {% endif %}
            {% endif %}

        </ul>
    {% endwith %}

</div>

以下是视图,以防万一:

应用/ views.py

def index(request):
    condo_list = Condo.objects.all().order_by('-timestamp_created')
    condo_filter = CondoFilter(request.GET, queryset=condo_list)

    paginator = Paginator(condo_filter.qs, MAX_CONDOS_PER_PAGE)
    page = request.GET.get('page')

    try:
        condos = paginator.page(page)
    except PageNotAnInteger:
        condos = paginator.page(1)
    except EmptyPage:
        condos = paginator.page(paginator.num_pages)


    return render(request, 'app/index.html', {
        'title': 'Home',
        'condos': condos,
        'page': page,
        'condo_filter': condo_filter,
    })

这是一个有效的例子:

答案 3 :(得分:1)

据我所知,您的目标是对过滤后的查询集进行分页。如果是这样,您可以将PublicationFilter对象的“qs”属性传递给Paginator构造函数:

def search(request):
    qs = local_url.objects.filter(global_url__id=1).all()
    url_filter = PublicationFilter(request.GET, queryset=qs)
    paginator = Paginator(url_filter.qs, 25)
    page = request.GET.get('page')
    try:
        pub = paginator.page(page)
    except PageNotAnInteger:
        pub = paginator.page(1)
    except EmptyPage:
        pub = paginator.page(paginator.num_pages)
    url_filter = PublicationFilter(request.GET, queryset=qs)
    return render(request, 'ingester/search_list.html', {'publication':pub})

url_filter.qs 包含已过滤的QuerySet
url_filter.queryset 包含未过滤的QuerySet

答案 4 :(得分:1)

我花了一些时间找到DRYer和更清洁的解决方案来解决此问题,我认为最好的解决方案是使用模板标签的解决方案。

from django import template

register = template.Library()

@register.simple_tag
def relative_url(value, field_name, urlencode=None):
    url = '?{}={}'.format(field_name, value)
    if urlencode:
        querystring = urlencode.split('&')
        filtered_querystring = filter(lambda p: p.split('=')[0] != field_name, querystring)
        encoded_querystring = '&'.join(filtered_querystring)
        url = '{}&{}'.format(url, encoded_querystring)
    return url

并在您的模板中

<a href="{% relative_url i 'page' request.GET.urlencode %}">{{ i }}</a>

来源:Dealing With QueryString Parameters

答案 5 :(得分:0)

要添加到答案中,我也使用html表以及django-filters和Paginator进行了此操作。以下是我的视图和模板文件。需要使用模板标记,以确保您将正确的参数传递给分页网址。

search_view.py

from django.shortcuts import render
from app.models.filters_model import ApiStatusFilter
from app.models.api_status import ApiStatus
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from datetime import datetime, timedelta

def status(request):
    all_entries_ordered = ApiStatus.objects.values().order_by('-created_at')[:200]

    for dictionarys in all_entries_ordered:
        dictionarys

    apistatus_list = ApiStatus.objects.values().order_by('-created_at')
    apistatus_filter = ApiStatusFilter(request.GET, queryset=apistatus_list)

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

    return render(request, 'status_page_template.html', {'dictionarys': dictionarys, 'apistatus_filter': apistatus_filter, 'dataqs': dataqs, 'allobjects': apistatus_list})

status_template.html

{% load static %}
{% load my_templatetags %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <link rel="stylesheet" type="text/css" href="{% static 'css/table_styling.css' %}">
        <meta charset="UTF-8">
        <title>TEST</title>
    </head>

    <body>
         <table>
            <thead>
                <tr>
                    {% for keys in dictionarys.keys %} 
                        <th>{{ keys }}</th>
                    {% endfor %}
                </tr>
            </thead>
                <form method="get">
                    {{ apistatus_filter.form.as_p }}
                    <button type="submit">Search</button>
                        {% for user in dataqs.object_list %}
                        <tr>
                            <td>{{ user.id }}</td>
                            <td>{{ user.date_time }}</td>
                            <td>{{ user.log }}</td>
                        </tr>
                        {% endfor %}
                </form>
            </tbody>
        </table>

        <div class="pagination">
            <span>
                {% if dataqs.has_previous %}
                    <a href="?{% query_transform request page=1 %}">&laquo; first</a>
                    <a href="?{% query_transform request page=dataqs.previous_page_number %}">previous</a>
                {% endif %}

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

                {% if dataqs.has_next %}
                    <a href="?{% query_transform request page=dataqs.next_page_number %}">next</a>
                    <a href="?{% query_transform request page=dataqs.paginator.num_pages %}">last &raquo;</a>
                {% endif %}
            </span>
        </div> 
    </body>
</html>

my_templatetags.py

from django import template

register = template.Library()

@register.simple_tag
def query_transform(request, **kwargs):
    updated = request.GET.copy()
    for k, v in kwargs.items():
        if v is not None:
            updated[k] = v
        else:
            updated.pop(k, 0)

    return updated.urlencode()

答案 6 :(得分:0)


实施步骤

  1. 通过pip install filter-and-pagination安装软件包
  2. 通过from filter_and_pagination import FilterPagination在view.py中导入FilterPagination
  3. 在您的函数中编写下面的代码作为标准...
queryset = FilterPagination.filter_and_pagination(request, Customer)
serialize_data = CustomerSerializer(queryset['queryset'], many=True).data
resultset = {'dataset': serialize_data, 'pagination': queryset['pagination']}
  • 在这段代码Customer中是Django模型&
  • CustomerSerializer是DRF序列化程序类
  1. 在结果集中,它包含数据集和分页数据,采用这种格式(API响应)链接:https://github.com/ashish1997it/filter-pagination-dj#demo
  2. 对于API请求,请遵循PostMan集合链接:https://github.com/ashish1997it/filter-pagination-dj#postman,在标头部分,它将带有一个参数,并要求您根据需要自定义

如果您仍然遇到任何困难,请与我联系:)

答案 7 :(得分:0)

我为分页结果“记住过滤器/查询URL参数”的方法:将当前URL参数作为上下文变量传递:

# views.py

class PublicationFilterView(FilterView):
    model = Publication
    filterset_class = PublicationFilter
    paginate_by = 15

    def get_context_data(self, *args, **kwargs):
        _request_copy = self.request.GET.copy()
        parameters = _request_copy.pop('page', True) and _request_copy.urlencode()
        context = super().get_context_data(*args, **kwargs)
        context['parameters'] = parameters
        return context
# templates/path/to/pagination.html

<a href="?page={{ page_obj.next_page_number }}&{{ parameters }}">
  Next
</a>