Ross
Ross

Reputation: 2417

Django Pagination & Filters appending to url rather than replacing

I have a Django page that has a table to display the data from my model. This table has pagination as well as multiple filters. I have manage to get the pagination and filters to work together to an extent, however the URL is all messed up. It looks like it is appending the new query string to the end of the URL.

I have two main issues with this:

  1. If I use a single filter, it adds all the empty query strings in the URL for all filters.
  2. If I have filtered data in the table and try to change the page, It append the page query string on the end rather than replace it.

Screenshot for issue 1:

enter image description here

Screenshot for issue 2:

enter image description here

filters.py:

class SetFilter(django_filters.FilterSet):
    name = CharFilter(field_name='name', lookup_expr='icontains', label='', )
    type = AllValuesFilter(field_name='type', choices=Set.objects.values_list('type', flat=True).distinct().order_by('type'), label='', empty_label="")
    nonfoil = AllValuesFilter(field_name='is_non_foil_only', choices=Set.objects.values_list('is_non_foil_only', flat=True).distinct().order_by('is_non_foil_only'), label='', empty_label="")
    foil = AllValuesFilter(field_name='is_foil_only', choices=Set.objects.values_list('is_foil_only', flat=True).distinct().order_by('is_foil_only'), label='', empty_label="")
    digital = AllValuesFilter(field_name='is_online_only', choices=Set.objects.values_list('is_online_only', flat=True).distinct().order_by('is_online_only'), label='', empty_label="")
    foreign = AllValuesFilter(field_name='is_foreign_only', choices=Set.objects.values_list('is_foreign_only', flat=True).distinct().order_by('is_foreign_only'), label='', empty_label="")

    class Meta:
        model = Set
        fields = ''

views.py

def sets_page(request):
    set_list = Set.objects.order_by('-id')
    last_modified = set_list[0].last_modified

    set_filter = SetFilter(request.GET, queryset=set_list)
    set_list = set_filter.qs

    paginator = Paginator(set_list, 22)
    is_paginated = True if paginator.num_pages > 1 else False
    page = request.GET.get('page') or 1
    try:
        current_page = paginator.page(page)
    except InvalidPage as e:
        raise Http404(str(e))
    context = {
        'last_modified': last_modified,
        'is_paginated': is_paginated,
        'current_page': current_page,
        'set_filter': set_filter
    }
    return render(request, "main/sets.html", context)

pagination.html

{% if current_page.has_next %}
    {% if 'name' in request.get_full_path %}
        <a class="page-link previous-next" href="{{ request.get_full_path }}&page={{ current_page.next_page_number }}">&#187;</a>
    {% else %}
       <a class="page-link previous-next" href="?page={{ current_page.next_page_number }}">&#187;</a>
    {% endif %}
{% else %}
    <a class="page-link previous-next" href="">&#187;</a>
{% endif %}

Upvotes: 0

Views: 571

Answers (1)

Redgren Grumbholdt
Redgren Grumbholdt

Reputation: 1230

I've been using a templatetag solution I found on here a while ago, could've referenced it, but I'll just post the snippet:

  1. Create a templatetag, if you dont know know how. Read here. It's quite easy and not that long a task.

  2. Add the following code in your filters/tags file:

@register.simple_tag(takes_context=True)
def param_replace(context, **kwargs):
    d =context['request'].GET.copy()
    for k,v in kwargs.items():
        d[k] = v
    for k in [k for k,v in d.items() if not v]:
        del d[k]
    return d.urlencode()

Load your custom filters in your template {% load "file_name_here" ... %}

Then on your pagination links:

<a class="page-link" href="?{% param_replace page=current_page.next_page_number %}"> Next </a>

Upvotes: 1

Related Questions