如何使用django_filter进行分页

时间:2018-07-17 20:38:56

标签: django filter django-filter

在TemplateView中使用django_filter后,我出现了分页问题。 在使用django_filter之前,我的分页功能正常,但现在它显示了每个页面中的所有项目,我一直在互联网上浏览,但是没有找到一个好的解决方案。 我该如何解决? 谢谢

我的filter.py

class SnippetFilter(django_filters.FilterSet):
    area = []
    tecnology = Technology.objects.values('parent_area').distinct().order_by('parent_area_id')
    for a in tecnology:                                                                         
        area.append(a['parent_area']) 

    parent_area = django_filters.ModelMultipleChoiceFilter(queryset=ApplicationArea.objects.filter(id__in=area), widget=forms.CheckboxSelectMultiple)

    class Meta:
        model = Technology
        fields = ['title', 'category', 'kind', 'patent', 'patent_type', 'parent_area']

我的view.py

class TechnologyListView(LoginRequiredMixin, ListView):
    model = Technology
    template_name = "technology/technology.html"
    paginate_by = 9

    def get_queryset(self, *args, **kwargs):
        queryset = super(TechnologyListView, self).get_queryset()
        if self.request.user.is_authenticated and self.request.user.is_superuser or self.request.user.is_authenticated and self.request.user.is_staff:
            queryset = Technology.objects.all()
        elif self.request.user.is_authenticated and self.request.user.is_technology:
            queryset = Technology.objects.filter(user=self.request.user).order_by('-id')
        return queryset

    def get_context_data(self, **kwargs):
        selected_elements = []
        data = super(TechnologyListView, self).get_context_data(**kwargs)
        if self.request.user.is_authenticated and self.request.user.is_technology:
            data['finished'] = Technology.objects.filter(user=self.request.user, category=0).count()
            data['developed'] = Technology.objects.filter(user=self.request.user, category=1).count()
            data['product'] = Technology.objects.filter(user=self.request.user, kind=0).count()
            data['process'] = Technology.objects.filter(user=self.request.user, kind=1).count()
            data['software'] = Technology.objects.filter(user=self.request.user, kind=2).count()
            data['deposited'] = Technology.objects.filter(user=self.request.user, patent=0).count()
            data['licensed'] = Technology.objects.filter(user=self.request.user, patent=1).count()
            data['donthave'] = Technology.objects.filter(user=self.request.user, patent=2).count()
        elif self.request.user.is_authenticated and self.request.user.is_superuser or self.request.user.is_authenticated and self.request.user.is_staff :          
            data['finished'] = Technology.objects.filter(category=0).count()
            data['developed'] = Technology.objects.filter(category=1).count()
            data['product'] = Technology.objects.filter(kind=0).count()
            data['process'] = Technology.objects.filter(kind=1).count()
            data['software'] = Technology.objects.filter(kind=2).count()
            data['deposited'] = Technology.objects.filter(patent=0).count()
            data['licensed'] = Technology.objects.filter(patent=1).count()
            data['dontthave'] = Technology.objects.filter(patent=2).count()

        data['filter'] = SnippetFilter(self.request.GET, queryset=self.get_queryset())

        return data

template.html

     <div class="container-fluid" >
        <div class="row">        
            <div class="col-sm-2">
                <div style="margin-top:20%; margin-bottom:25% ">
                    <h1 class="title text-center">Filtro:</h1>
                    <form method="GET" action="{% url 'technology:tech_index' %}" novalidate>
                        {{filter.form|bootstrap}}

                        <a class="btn btn-rw btn-danger" href="{% url 'technology:tech_index' %}">Limpar Filtro</a>
                        <input type='submit' value='Procurar' class='btn btn-rw btn-primary'>                    
                    </form>
                </div>
            </div>

            <div class="col-sm-8 col-sm-offset-1">
                <br>                  
                <a class="btn btn-rw btn-primary" href="{% url 'technology:create_tech' %}"><i class="fa fa-bolt">
                </i>Adicionar Tecnologia</a>                            


                <h1 class="title text-center">Minhas Tecnologias</h1>


                {% if filter.qs.count > 0 %}


                <div class="tab-content tab-shop mt15" style="align-items: center !important;">
                    <div class="row" >
                        <div class="col-sm-4 col-md-4 col-lg-4">
                            <canvas id="category"></canvas>
                        </div>  
                        <div class="col-sm-4 col-md-4 col-lg-4">
                            <canvas id="type" ></canvas>
                        </div>    
                        <div class="col-sm-4 col-md-4 col-lg-4">
                            <canvas id="patent"></canvas>
                        </div> 
                        <!-- <div class="col-lg-3 col-md-3 col-sm-3">
                            <canvas id="area_ap" width="80" height="80"></canvas>
                        </div>   -->
                    </div>
                    <br>
                </div>
                <br>
                <div class="tab-content tab-shop mt15">


                    <div id="home" class="tab-pane row fade in active">

                        {% for item in filter.qs %}        
                        <div class="col-lg-4 col-md-4 col-sm-6 mb30">
                            <div class="view  no-margin" style="background-color: #cfcfcf">
                                <!-- Blog Thumb -->
                                <div class="product-container">

                                    {% if item.area_img %}                                                      
                                    <img class="img-responsive full-width" style="width:100%; height:200px" src="{{item.area_img.image.url}}" alt="..."> 
                                    {% else %}
                                    <img class="img-responsive full-width" style="width:100%; height:200px" src="{% static 'images/notavailable.png' %}" alt="...">                                                
                                    {% endif %}                                                                                          

                                </div>
                                <div class="mask">
                                    <div class="image-hover-content">
                                            <!-- Zoom + Blog Link -->
                                            <a href="{% url 'technology:detail_tech' item.pk %}"  >
                                                <div class="image-icon-holder"><span data-toggle="tooltip" data-placement="top" title="Visualizar" class="ion-eye image-icons"style="color:#fff"></span></div>
                                            </a>
                                            {% if request.user.is_authenticated and request.user.is_technology %}                                                                                                      
                                                <a href="{% url 'technology:update_tech' item.pk %}">
                                                    <div class="image-icon-holder"><span  data-toggle="tooltip" data-placement="top" title="Editar" class="ion-edit image-icons" style="color:#fff"></span></div>
                                                </a>
                                                <a data-toggle="modal" data-target="#delete-{{item.pk}}">
                                                    <div class="image-icon-holder"><span data-toggle="tooltip" data-placement="top" title="Deletar" class="ion-ios7-trash image-icons" style="color:red"></span></div>
                                                </a>
                                                {% endif %}

                                                <div class="modal fade" id="delete-{{item.pk}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
                                                    <div class="modal-dialog" role="document">
                                                        <div class="modal-content text-center">
                                                            <form action="{% url 'technology:delete_tech' pk=item.pk %}" method="post">
                                                                {% csrf_token %}
                                                                <div class="modal-header">
                                                                    <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                                                                    <h2>Deletar</h2>
                                                                </div>
                                                                <div class="modal-body">
                                                                    <p>Você deseja realmente deletar "{{ item }}"?</p>
                                                        </div>
                                                        <div class="modal-footer">
                                                            <button type="button" class="btn btn-success" data-dismiss="modal">Voltar</button>
                                                            <input class="btn btn-danger" type="submit" value="Confirmar" />
                                                        </div>
                                                    </form>
                                                    </div>
                                                </div>
                                            </div>

                                        </div><!-- /image hover content -->
                                    </div><!-- /mask-->
                                </div>
                                <div class="shop-product content-box-shadow">
                                    <a href="{% url 'technology:update_tech' item.pk %}"><h2>{{item.title}}</h2></a>
                                    {% if item.description %}                                          
                                        <p>{{item.description|truncatechars:40}}</p>
                                    {% else %}
                                        <p class="text-danger">Não há descrição</p>
                                    {% endif %}
                                </div>
                            </div>
                            {% if forloop.counter|divisibleby:4 %}
                        </li>
                            <li>
                                {% endif %}
                    {% endfor %}
                </div>
            </div>
            {% include "includes/paginator.html" %}
            {% else %}
            <div class="tab-content tab-shop mt15 text-center " style="padding-top: 25%; padding-bottom: 25%">
                <div class="row">
                    <h1 class="text-info">Nenhuma tecnologia cadastrada</h1>
                </div>
            </div>
            {% endif %}
        </div>
    </div>

paginator.html

{% if is_paginated %}
    <ul class="pagination">
        {% if page_obj.has_previous %}
            <li class="page-item">
                <a href="?page={{ page_obj.previous_page_number }}">&laquo;</a>
            </li>
        {% else %}
            <li class="disabled"><span class="page-link">&laquo; 
            </span></li>
        {% endif %}

         {% for page_num in paginator.page_range %}
             {% if page_obj.number == page_num %}
                 <li class="page-item active">
                    <span class="page-link">
                       {{ page_num }}
                       <span class="sr-only">(current)</span>
                    </span>
                 </li>
             {% elif page_num > page_obj.number|add:'-2' and page_num < page_obj.number|add:4 %}
                 <li class="page-item">
                     <a class="page-link" href="?page={{ page_num }}">{{page_num}}</a>
                 </li>
             {% endif %}
          {% endfor %}


          {% if page_obj.has_next %}
             <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.next_page_number }}">&raquo;</a></li>
          {% else %}
              <li class="page-item disabled">
                  <span class="page-link">
            &raquo;
                  </span>
              </li>
          {% endif %}


    </ul>
 {% endif %}

3 个答案:

答案 0 :(得分:3)

我有一段时间了,发现该解决方案是我的最爱。

django-filter的FilterView已经支持与ListView相同的分页,但是如何使它工作不是很明显。您可以通过在应用过滤器时更改浏览器地址栏中的“ page = 2”来进行尝试,并确保将其转到下一个正确的页面。

因此使其工作仅需几个步骤...

创建一个视图混合,将'page'关键字分隔出来(django的分页默认),然后将剩余的查询字符串作为新的模板上下文变量返回。

class PaginatedFilterViews(View):
    def get_context_data(self, **kwargs):
        context = super(PaginatedFilterViews, self).get_context_data(**kwargs)
        if self.request.GET:
            querystring = self.request.GET.copy()
            if self.request.GET.get('page'):
                del querystring['page']
            context['querystring'] = querystring.urlencode()
        return context

然后将这个新对象包含在您要分页的所有FilterView中...即:

class FilteredList(PaginatedFilterViews, FilterView):
    model = Whatever
    paginate_by = 10 # or whatever
    # the rest of your view code

并更新分页模板以插入django-filter的其余查询字符串...

{% if page_obj.has_previous %}
    <li>
        <a href="?page=1{% if querystring %}&amp;{{ querystring }}{% endif %}">
            <i class="icon-page-first"></i>
            <span class="btn-text">First</span>
        </a>
    </li>
    <li>
        <a href="?page={{ page_obj.previous_page_number }}{% if querystring %}&amp;{{ querystring }}{% querystring %}">
            <i class="icon-page-back"></i>
            <span class="btn-text">Prev</span>
        </a>
    </li>
{% else %}
    <li class="disabled">
        <span class="icon-page-first">
            <span class="btn-text">First</span>
        </span>
    </li>
    <li class="disabled">
        <span class="icon-page-back">
            <span class="btn-text">Prev</span>
        </span>
    </li>
    {# etc etc #}
{% endif %}

对于我来说,在许多视图中都可以很好地工作,不需要其他任何第三方依赖。

答案 1 :(得分:1)

我个人将django-tables与django-filter一起使用,并且这为我处理了分页,所以我不是这方面的专家。但是,一旦您将其显示在视图中,似乎需要对过滤器的结果进行分页。也许像这样吗?

paginator = Paginator(data, 10)

查看有关SO的帖子。 Django Filter with Pagination以及该网站还介绍了一般操作方法。 https://djangopy.org/how-to/pagination-with-django/

答案 2 :(得分:1)

晚答复,但我将与我分享我的解决方案。

我遇到了同样的问题,django-filter和分页都可以单独正常工作,但是结合使用时,只会过滤第一页。

这是因为django-filters将过滤器参数与请求一起发送,并且分页功能相同。因此,当您在django-filter表单上单击Submit时,查询的参数将附加到请求中。看起来可能像这样:

'/?name =&project =&status = 1'

简单地,当您点击下一页时,您可能会将其设置为将页码附加到请求的链接。可能看起来像这样:

'/?page = 2'

我发现的解决方案很笨拙,但是可以用。我所做的就是阅读请求字典,并创建一个格式为&& {parameter_name} = {parameter_value}的字符串以通过上下文,并附加到分页链接。

此循环如下:

views.py

new_request = ''
for i in request.GET:
    if i != 'page':
        val = request.GET.get(i)
        new_request += f"&{i}={val}"
context = {...'new_request':new_request...}

然后您可以在分页链接href:

的末尾将其添加到模板中
<a href="?page={{ page_obj.next_page_number }}{{ new_request }}">Next</a>

这将在浏览页面时通过GET请求保留您对过滤器的选择。