Search code examples
pythondjangourlviewpagination

Pagination of search results only in Django not working


I have implemented a search bar and function into a django web app in the following view:

def search_products(request):
    search_query = request.GET.get('search', '')
    products = Product.objects.filter(Q(name__icontains=search_query) | Q(brand__icontains=search_query))
    paginator = Paginator(products, 40)
    page_number = request.GET.get('page', 1)
    page = paginator.get_page(page_number)
    if page.has_next():
        next_url = f'?page={page.next_page_number()}'
    else:
        next_url = ''

 

    if page.has_previous():
        prev_url = f'?page={page.previous_page_number()}'
    else:
        prev_url = ''

 

    return render(request, 'store/search_products.html',
                  context={'products': page.object_list, 'page': page, 'next_page_url': next_url,
                           'prev_page_url': prev_url})

The URLs are setup as follows:

urlpatterns = [
    path('', views.store_view, name='store'),
    path('wishlist/', views.wishlist_view, name='wishlist'),
    path('update_item/', views.updateItem, name='update_item'),
    path('search_products/', views.search_products, name='search_products'),
]

And the HTML for the search results is as follows:

<nav aria-label="Page navigation example">
          <ul class="pagination">
            <li class="page-item {% if not prev_page_url %} disabled {% endif %}">
              <a class="page-link" href="{{  prev_page_url }}" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
              </a>
            </li>

 

            {% for n in page.paginator.page_range %}
              {% if page.number == n %}
                <li class="page-item active" aria-current="page">
                    <a class="page-link" href="?page={{ n }}">{{ n }}
                    <span class="sr-only"></span>
                    </a></li>
              {% elif n > page.number|add:-4 and n < page.number|add:4 %}
                <li class="page-item">
                    <a class="page-link" href="?page={{ n }}">{{ n }}</a>
                </li>
                {% endif %}
            {% endfor %}

 


            <li class="page-item {% if not next_page_url %} disabled {% endif %}">
              <a class="page-link" href="{{ next_page_url  }}" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
              </a>
            </li>
          </ul>
        </nav>

I think the issue may be due to the fact that the search query enters the URL before the page number (?page={{ n }}), this may be wrong however. I am not sure how to fix this or implement this change. Any help would be appreciated.


Solution

  • The reason that your pagination is not working is that when you click on another page link the page query parameter replaces the search query parameter and your search results will be gone.
    The solution is to to append page query parameter to search query parameter it will be some thing like this for example: url/?search=example&page=2
    This is how you can do that:

    1. Inside your app directory create a folder called templatetags

    2. Inside the templatetags folder create a file called pagination_tags.py(name is up to you)

      # Your template tag in app_name/templatetags/pagination_tags.py
      
      from django import template
      from urllib.parse import urlencode
      
      
      register = template.Library()
      
      @register.simple_tag
      def url_replace (request, field, value):
          dict_ = request.GET.copy()
          dict_[field] = value
      
          return dict_.urlencode()
      
    3. After creating your template tag load it in your html page and use it

      <!-- load your templatetag in your html file -->
      <!-- you should load your .py file -->
      {% load pagination_tags %}
      <!-- now you can use it -->
      
      <!-- Here is an Example to know how to use it -->
      <a class="page-link text-dark" href="?{% url_replace request 'page' 1 %}">1</a>
      <!-- first param is request , second param is is your lookup field and third param is your page number -->