1

I've a small Django project basic-pagination. There is one model, one form and two views (list view, form view). User submits data in the form view, then the data is displayed in the list view. Pagination is enabled to only display 5 posts at a time.

What I've implemented is a form with a GET response to get the data I want to display (e.g. name, date). See code below

class FormListView(ListView):
    model = models.ToDoList
    paginate_by = 5  # if pagination is desired
    template_name = 'pagination/listview.html'
    context_object_name = 'forms'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = 'Form List View'
        context['filter_form'] = forms.FilterListView(self.request.GET)
        return context

    def get_queryset(self):
        queryset = models.ToDoList.objects.all().order_by('-id')
        name = self.request.GET.get('name')
        if name:
            queryset = queryset.filter(name=name)
        order_by = self.request.GET.get('order_by')
        if order_by:
            queryset = queryset.order_by(order_by)
        print(queryset)
        return queryset

The problem is that the class based view ListView calls the method get_queryset if you are moving from page 1 to page 2 and thus losing the filtered queryset I wanted.

How can I maintain the filtering throughout the pagination process?

Jon
  • 2,373
  • 1
  • 26
  • 34
  • 2
    This has nothing to do with the view: it is in your template that you write URLs that do not use the other parameters from the query, but only the `page` parameter. – Willem Van Onsem Jan 29 '20 at 17:43
  • @WillemVanOnsem do you have a suggested fix for that? – Jon Jan 29 '20 at 17:47
  • Have you seen this SO [post](https://stackoverflow.com/questions/8386191/django-paginating-in-template-using-multiple-get-parameters) which looks like it is dealing with a related topic? – Chris Jan 29 '20 at 18:04
  • @Chris I think I found a fix. I changed the `href` for each link. For example, `href="?page={{ page_obj.next_page_number }}"` --> `href="?page={{ page_obj.next_page_number }}&{{ request.GET.urlencode }}"` – Jon Jan 29 '20 at 18:13

2 Answers2

3

As @WillemVanOnsem pointed out, the problem is not with the view, but rather with the URLs in the template (templates/pagination/listview.html). Previously, the next button had href="?page={{ page_obj.next_page_number }}" which meant that request.GET would only contain the page number for pagination and not the other filter and order by criteria.

The solution was then to append request.GET.urlencode to href like

<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.next_page_number }}&{{ request.GET.urlencode }}">Next</a>

However, this is not a total fix because simply appending request.GET also appends the page number you're currently at. Simply put, if you jump from page 1 to 2 to 3, you will end up with a URL that looks like

http://localhost:8000/listview/?page=1&page=2&page=3...

The request.GET is a QueryDict like <QueryDict: {'page': ['1'], ...}>. A solution to this was to simply pop the page parameter, however, because request.GET is immutable you first have to make a copy of it. Essentially, I added the following lines to get_context_data method in the ListVew

def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['title'] = 'Form List View'
    context['filter_form'] = forms.FilterListView(self.request.GET)
    get_copy = self.request.GET.copy()
    if get_copy.get('page'):
        get_copy.pop('page')
    context['get_copy'] = get_copy
    return context

And in the template I called the get_copy object like href="?page={{ page_obj.next_page_number }}&{{ get_copy.urlencode }}"

For the entire template example follow templates/pagination/listview.html

Not the most elegant solution, but I feel it's simple enough for most people to utilize.

Jon
  • 2,373
  • 1
  • 26
  • 34
0

I was with the same problem and I solved it with the link below.

https://www.caktusgroup.com/blog/2018/10/18/filtering-and-pagination-django/

Paulista
  • 1
  • 3
  • Could you add context as to what/how you solved the issue? Linking to an external site doesn't suffice as an answer – Jon Aug 12 '22 at 19:20