Home > OS >  How do I fix pagination when there is a GET filter from the URL?
How do I fix pagination when there is a GET filter from the URL?

Time:11-19

In the main product browse page (www.url.com/works), pagination works well (displays 10 items at a time) and the URL becomes www.url.com/works/?page=2

In the same view, the works can be filtered by category (i.e. www.url.com/works/?collection=Drawing). Since it using the same view, it is still paginating by 10, but if I click other pages, it loses the /?collection=Drawing and just goes back to being www.url.com/works/?page=2.

How do I combine them to be something like www.url.com/works/?collection=Drawing&page=2 ?

Thank you!

views.py

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from url_filter.filtersets import ModelFilterSet
    
class ProductListView(ListView):
model = Product
template_name = "products/product_all.html"
paginate_by = 10

def get_queryset(self, *args, **kwargs):
    sold = ProductPurchase.objects.filter(
        refunded=False
    ).values_list('product_id')
    qs = super(ProductListView, self).get_queryset(**kwargs)
    qs = qs.filter(for_sale=True, test_check=False).exclude(id__in=sold).order_by('-timestamp')

    categoryfilter = self.request.GET.get("collection")
    if categoryfilter:
        qs = qs.filter(
            Q(category__name__icontains=categoryfilter)
        )

    query = self.request.GET.get("q")
    if query:
        tags = Tag.objects.filter(
            slug=query
        ).values_list('products')
        qs = qs.filter(
            Q(title__icontains=query) |
            Q(description__icontains=query) |
            Q(material__icontains=query) |
            Q(id__in=tags)
        ).order_by("title")

    return MyFilterSet(data=self.request.GET, queryset=qs).filter()

product_all.html

<section class="mt-5">
  <div class="container">
            
      <div class="row mx-1 mb-5">
          <div class="py-0 my-0">
            <span class="hero-heading px-2 mr-2 text-sm"><a href="{% url 'products:list' %}">All</a></span>
            <span class="hero-heading px-2 mr-2 text-sm"><a href="?collection=Painting">Painting</a></span>
            <span class="hero-heading px-2 mr-2 text-sm"><a href="?collection=Drawing">Drawing</a></span>
            <span class="hero-heading px-2 mr-2 text-sm"><a href="?collection=Print">Print</a></span>
            <span class="hero-heading px-2 mr-2 text-sm"><a href="?collection=Sculpture">Sculpture/ Installation</a></span>
            <span class="hero-heading px-2 mr-2 text-sm"><a href="?collection=Textiles">Textiles</a></span>
            <span class="hero-heading px-2 mr-2 text-sm"><a href="?collection=Photography">Photography</a></span>
            <span class="hero-heading px-2 mr-2 text-sm"><a href="?collection=Mixed media">Mixed media</a></span>
          </div>
      </div>


            <div class="row">

              <!-- Grid -->
              <div class="products-grid col-xl-12 col-lg-8 order-lg-2">
                
                <div class="card-columns product-columns">
                  {% include "products/product_list_snippet.html" with object_list=products %}
                  
                </div>
                

                <nav aria-label="page navigation" class="d-flex justify-content-center mb-5 mt-3">
                  <ul class="pagination">
                    {% if page_obj.has_previous %}
                    <li class="page-item"><a href="?page={{ page_obj.previous_page_number }}" aria-label="Previous" class="page-link"><span aria-hidden="true">Prev</span><span class="sr-only">Previous</span></a></li>
                    {% endif %}

                    {% for i in paginator.page_range %}
                      {% if page_obj.number == i %}
                    <li class="page-item active"><a href="#" class="page-link">{{ i }}</a></li>
                      {% else %}
                    <li class="page-item"><a href="?page={{ i }}" class="page-link">{{ i }}</a></li>
                      {% endif %}
                    {% endfor %}

                    {% if page_obj.has_next %}
                    <li class="page-item"><a href="?page={{ page_obj.next_page_number }}" aria-label="Next" class="page-link"><span aria-hidden="true">Next</span><span class="sr-only">Next     </span></a></li>
                    
                    {% endif %}
                  </ul>
                </nav>
              </div>

      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
      <script type="text/javascript">
      jQuery(document).ready(function() {
        
        var btn = $('#button');

        $(window).scroll(function() {
          if ($(window).scrollTop() > 300) {
            btn.addClass('show');
          } else {
            btn.removeClass('show');
          }
        });

        btn.on('click', function(e) {
          e.preventDefault();
          $('html, body').animate({scrollTop:0}, '1000');
        });

      });

      </script>


      </div>
      </div>

CodePudding user response:

You can add a method to the view to obtain an URL-encoded queryset of all items except the page with:

class ProductListView(ListView):
    # …

    def querystring_url(self):
        data = self.request.GET.copy()
        data.pop(self.page_kwarg, None)
        return data.urlencode()

Then in the template you can write a link to a page, for example with:

<a href="?page={{ page_obj.previous_page_number }}&amp;{{ view.querystring_url }}">…</a>

You should update all the links with a different page such that these make use of the querystring_url of the view.

  • Related