how can I use pagination with django_filter

后端 未结 3 1443
孤独总比滥情好
孤独总比滥情好 2021-01-15 05:09

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 e

相关标签:
3条回答
  • 2021-01-15 05:40

    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.

    0 讨论(0)
  • 2021-01-15 05:52

    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/

    0 讨论(0)
  • 2021-01-15 05:52

    late reply but I'll share my solution for future people.

    I was having the same problem, both the django-filter, and pagination work properly on their own, but when combined it would only filter the first page.

    This is because django-filters sends the filter parameters through with the request, and the pagination does the same. Therefore when you hit submit on the django-filter form, the parameters for your query get appended to the request. This might look something like:

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

    Similarily, when you hit next page, you likely have it set up as a link which appends the page number to the request. Might look something like:

    '/?page=2'

    The solution I found is pretty hacky, but it works. What I did was read the request dictionary and create a string with the format: &{parameter_name}={parameter_value} to pass through the context, and append to the pagination links.

    This loop looks like:

    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...}
    

    You can then add this in your template at the end of the pagination link href:

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

    This will preserve your filter selection through GET requests when going through pages.

    0 讨论(0)
提交回复
热议问题