0
votes

I've made a filter form using Django, which returns a list of paginated matches.

When I initially run the filter, I get the correct number of pages showing. However, when I click on another page number, the page then reverts to that relevant page number for the unfiltered results. For example, I filter the results on 'Bug' and I get all the paginated results for tickets with a type of 'Bug'. The pagination shows the links to the different pages (1, 2, 3, etc.) and also the next and last buttons. However, if I click on '3', the results revert to the unfiltered results, I'm given the results for page 3 of the unfiltered results instead of page 3 of the filtered results, and the total number of pages for the unfiltered results show in the pagination links.

Please could anybody help me to understand how to fix the issue and keep the filtered results when navigating through the pagination?

all_tickets.html:

// filter form code //

// Displayed results (unfiltered results displayed when page is first loaded) //

<!-- Pagination - only visible if there are multiple pages -->
{% if tickets.has_other_pages %}
    <ul class="pagination center-align">
        <!-- Previous/First button - only visible if previous page available -->
        {% if tickets.has_previous %}
            <!-- First page button -->
            <li>
                <a href="?page=1">
                    <i class="fas fa-angle-double-left" aria-hidden="true"></i>
                </a>
            </li>
            <!-- Previous page button -->
            <li>
                <a href="?page={{ tickets.previous_page_number }}">
                    <i class="fas fa-angle-left" aria-hidden="true"></i>
                </a>
            </li>
        {% endif %}

        <!-- Show link to current page and only few other surrounding pages, not all -->
        {% for num in tickets.paginator.page_range %}
            <!-- Show the current page number but disable it -->
            {% if tickets.number == num %}
                <li class="disabled">
                    <a>
                        {{ num }}
                    </a>
                </li>
            <!-- Show the 4 surrounding (2 next and 2 previous) pages -->
            {% elif num > tickets.number|add:'-3' and num < tickets.number|add:'3' %}
                <li>
                    <a href="?page={{ num }}">
                        {{ num }}
                    </a>
                </li>
            {% endif %}
        {% endfor %}

        <!-- Next/Last button - only visible if previous page available -->
        {% if tickets.has_next %}
            <!-- Next page button -->
            <li>
                <a href="?page={{ tickets.next_page_number }}">
                    <i class="fas fa-angle-right" aria-hidden="true"></i>
                </a>
            </li>
            <!-- Last page button -->
            <li>
                <a href="?page={{ tickets.paginator.num_pages }}">
                    <i class="fas fa-angle-double-right" aria-hidden="true"></i>
                </a>
            </li>
        {% endif %}

    </ul>
{% endif %}

search view in views.py file:

def view_all_tickets(request):
    '''
    View all tickets
    Allows users to filter tickets based on type or status
    '''
    tickets = Ticket.objects.all()
    page = request.GET.get('page', 1)
    ticket_type_dropdown = TicketType.objects.all()
    ticket_status_dropdown = TicketStatus.objects.all()

    # Query parameters
    ticket_type = request.GET.get("ticket_type")
    ticket_status = request.GET.get("ticket_status")

    # Filter by query parameters
    if ticket_type:
        tickets = tickets.filter(ticket_type__id=ticket_type)
    else:
        tickets

    if ticket_status:
        tickets = tickets.filter(ticket_status__id=ticket_status)
    else:
        tickets

    # Pagination
    paginator = Paginator(tickets, 1)

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

    args = {
        "tickets": tickets,
        "ticket_type_dropdown": ticket_type_dropdown,
        "ticket_status_dropdown": ticket_status_dropdown,
    }

    return render(request, "all_tickets.html", args)
1

1 Answers

1
votes

You need to include all the query params in every link. So you should pass them back to the template and add them to the params:

args = {
    "tickets": tickets,
    "ticket_type_dropdown": ticket_type_dropdown,
    "ticket_status_dropdown": ticket_status_dropdown,
    "ticket_type": ticket_type,
    "ticket_status": ticket_status,
}

return render(request, "all_tickets.html", args)

...

<a href="?page={{ tickets.previous_page_number }}&ticket_type={{ ticket_type }}&ticket_status={{ ticket_status }}">
etc.

To make this easier you could define a template filter that outputs the existing link automatically and allows you to append only the page number variable, some of the third-party pagination libraries probably include this.