Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how can I use pagination with django_filter

I got a problem with pagination after using django_filter in my TemplateView. Before use django_filter, my pagination was working normally but now it show all the items in every page, I've been looking on the internet but I didn't find a good solution for this. how can I fix it? thanks

my 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']

my 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 %}
like image 698
Diogo Silva Avatar asked Sep 07 '25 01:09

Diogo Silva


2 Answers

I had this issue for awhile, and found this solution to be my favourite.

django-filter's FilterView already supports pagination the same as ListView, except it's not super obvious how to make it work. You can try this by changing 'page=2' in the address bar of your browser while the filters are applied and sure enough it will go to the next correct page.

So to make it work is only a few steps...

Create a view mixin, which separates out 'page' keyword (default for django's pagination) and returns the remaining query string as a new template context variable.

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

Then include this new object in all the FilterViews you want paginated... ie:

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

And update your pagination template to insert the rest of django-filter's query string...

{% 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 %}

Works well for me across many views, and no other 3rd party dependencies are required.

like image 119
D. Starr Avatar answered Sep 10 '25 09:09

D. Starr


Personally I use django-tables with django-filter and that takes care of the pagination for me, so I'm no expert on this. However it seems that you need to paginate the results of the filter once you have them in your view. Perhaps something like this?

paginator = Paginator(data, 10)

Check out this posting on SO. Django Filter with Pagination and also this website explains how to do it generically. https://djangopy.org/how-to/pagination-with-django/

like image 31
cander Avatar answered Sep 10 '25 09:09

cander