In a Django CBV (ListView), after submitting a form using GET method, with filter_1 and filter_2 fields, the resulting URL I get is something like:
http://example.com/order/advanced-search?filter_1=foo&filter_2=bar
Everything is ok.
However, I'd like to use pagination, proving to my template a URL like:
http://example.com/order/advanced-search?page=2&filter_1=foo&filter_2=bar
Let's say I could override this method for this purpose:
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['my_form_values'] = self.request.GET
Now, how can I use my_form_values in my pagination template to display the right URLs?
For now, here is my (simplified) pagination template code:
{% for num in page_obj.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">
<span class="page-link">{{ num }}</span>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ num }}">{{ num }}</a>
</li>
{% endif %}
{% endfor %}
I do it this way
#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()
and then the pagination in template
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link"
href="?{% param_replace page=1 %}">{% trans 'first' %}</a>
</li>
<li class="page-item"><a class="page-link"
href="?{% param_replace page=page_obj.previous_page_number %}">{{ page_obj.previous_page_number }}</a>
</li>
{% endif %}
<li class="page-item active"><a class="page-link"
href="?{{ page_obj.number }}">{{ page_obj.number }}</a>
</li>
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link"
href="?{% param_replace page=page_obj.next_page_number %}">{{ page_obj.next_page_number }}</a>
</li>
<li class="page-item"><a class="page-link"
href="?{% param_replace page=page_obj.paginator.num_pages %}">{% trans 'last' %}</a>
</li>
{% endif %}
</ul>
Related
I am filtering my data, and also applying paginator, I have found some solution and I used it but it is working only for the next button and not for previous and button numbers in between i.e. for {{i}} (Django, python)
this is template_tag file
myapp_extra.py
from django import template
register = template.Library()
#register.simple_tag
def my_url(value, field_name, urlencode=None):
url = '?{}={}'.format(field_name, value)
if urlencode:
querystring = urlencode.split('&')
filterd_querystring = filter(lambda p: p.split('=')[0]!=field_name, querystring)
encoded_querystring = '&'.join(filterd_querystring)
url = '{}&{}'.format(url, encoded_querystring)
return url
in my html
{% load myapp_extra %}
<other code>
<nav>
<ul class="pagination rounded-separated justify-content-center" style="float: right; margin-top: 1%;">
{% if employees_attendance_list.has_previous %}
<li class="page-item"><a class="page-link" href="{% my_url employees_attendance_list.previous_page_number 'page' request.GET.urlencode }"><i class="mdi mdi-chevron-left"></i></a></li>
{% else %}
<li class="disabled"></li>
{% endif %}
{% for i in employees_attendance_list.paginator.page_range %}
{% if employees_attendance_list.number == i %}
<li class="page-item active"><a class="page-link" >{{ i }}</a></li>
{% else %}
<li class="page-item"><a class="page-link" href="{% my_url i 'page' request.GET.urlencode}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if employees_attendance_list.has_next %}
<li class="page-item"><a class="page-link" href="{% my_url employees_attendance_list.next_page_number 'page' request.GET.urlencode %}"><i class="mdi mdi-chevron-right"></i></a></li>
{% else %}
<li class="disabled"></li>
{% endif %}
</ul>
</nav>
in views
page = request.GET.get('page', 1)
paginator = Paginator(employees_attendance, settings.PAGE_LIMIT)
try:
employees_attendance_list = paginator.page(page)
except PageNotAnInteger:
employees_attendance_list = paginator.page(1)
except EmptyPage:
employees_attendance_list = paginator.page(paginator.num_pages)
I have made some changes in my html
<nav>
<ul class="pagination rounded-separated justify-content-center" style="float: right; margin-top: 1%;">
{% for i in employees_attendance_list.paginator.page_range %}
<li class="page-item">
<a class="page-link" href="{% my_url i 'page' request.GET.urlencode %}">{{ i }}</a>
</li>
{% endfor %}
</ul>
</nav>
I have some pagination for a table. I have it so that it will only show 3 pages either side of the current page. However if I am on the 5th page, The first page disappears. I am trying to set it up so that the first two and last two pages of the pagination are always visible regardless of what the current page is.
code:
{% if is_paginated %}
<div class="pagination">
{% if current_page.has_previous %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="?page={{ current_page.previous_page_number }}">«</a>
{% else %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="">«</a>
{% endif %}
{% for i in current_page.paginator.page_range %}
{% if i == 1 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endif %}
{% if i == 2 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endif %}
{% if i != 1 and i != 2 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
{% if current_page.number|add:-4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% if current_page.number|add:3 >= i and current_page.number|add:-3 <= i %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% if current_page.number|add:4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% if current_page.has_next %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="?page={{ current_page.next_page_number }}">»</a>
{% else %}
<a class="page-link" style="font-size: 24px; padding: 2px;" href="">»</a>
{% endif %}
</div>
{% endif %}
Screenshot:
Update:
I have worked out a jank way of having the first two pages always showing but cannot get the last two pages to always show
I add some well place if statements to always display the first and last place.
I set it so that if i == 1 show the page in the pagination navbar. Then during the loop of i I remove the first page and last page using i != 1 and i != current_page.paginator.page_range|last.
Using current_page.paginator.page_range|last will get the last value in the range and then you do the same for the last page as you did for the first page.
Code:
{% for i in current_page.paginator.page_range %}
{% if i == 1 %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% endif %}
{% if i != 1 and i != current_page.paginator.page_range|last %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ i }}</a>
{% else %}
{% if current_page.number|add:-4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% if current_page.number|add:3 >= i and current_page.number|add:-3 <= i %}
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
{% endif %}
{% if current_page.number|add:4 == i %}
<a class="page-link" href="">...</a>
{% endif %}
{% endif %}
{% endif %}
{% if i == current_page.paginator.page_range|last %}
{% if current_page.number == i %}
<a class="page-link active" href="">{{ current_page.paginator.page_range|last }}</a>
{% else %}
<a class="page-link" href="?page={{ current_page.paginator.page_range|last }}">{{ current_page.paginator.page_range|last }}</a>
{% endif %}
{% endif %}
{% endfor %}
Screenshot:
I'm trying to set up pagination within my Django project but I can't find a way to make the filters (ptags in my case) follow to the next pages.
Ps; I use Django-haystack with faceting for filtering.
I have a custom forms.py
from haystack.forms import FacetedSearchForm
class FacetedProductSearchForm(FacetedSearchForm):
def __init__(self, *args, **kwargs):
data = dict(kwargs.get("data", []))
self.ptag = data.get('ptags', [])
super(FacetedProductSearchForm, self).__init__(*args, **kwargs)
def search(self):
sqs = super(FacetedProductSearchForm, self).search()
if self.ptag:
query = None
for ptags in self.ptag:
if query:
query += u' OR '
else:
query = u''
query += u'"%s"' % sqs.query.clean(ptags)
sqs = sqs.narrow(u'ptags_exact:%s' % query)
return sqs
That I pass in my Views:
class FacetedSearchView(BaseFacetedSearchView):
form_class = FacetedProductSearchForm
facet_fields = ['ptags']
template_name = 'search_result.html'
paginate_by = 3
context_object_name = 'object_list'
Here's my full search_result.html:
<div>
{% if page_obj.object_list %}
<ol class="row top20" id="my_list">
{% for result in page_obj.object_list %}
<li class="list_item">
<div class="showcase col-sm-6 col-md-4">
<div class="matching_score"></div>
<a href="{{ result.object.get_absolute_url }}">
<h3>{{result.object.title}}</h3>
<h5>{{ result.object.destination }}</h5>
<img src="{{ result.object.image }}" class="img-responsive">
</a>
<div class="text-center textio">
<ul class="tagslist">
<li class="listi">
{% for tags in result.object.ptags.names %}
<span class="label label-info"># {{ tags }}</span>
{% endfor %}
</li>
</ul>
</div>
</div>
</li>
{% endfor %}
</ol>
</div>
I'm able to pass the query which is a destination to the next page by adding this at the bottom of my html:
{% if is_paginated %}
<ul class="pagination pull-right">
{% if page_obj.has_previous %}
<li><i class="fas fa-angle-left"></i>Previous page</li>
{% else %}
<li class="disabled"><span><i class="fas fa-angle-left"></i>Previous page</span></li>
{% endif %}
{% if page_obj.has_next %}
<li>See more results<i class="fas fa-angle-right"></i></li>
{% else %}
<li class="disabled"><span>See more results<i class="fas fa-angle-right"></i></span></li>
{% endif %}
</ul>
{% endif %}
{% else %}
<p> Sorry, no result found for the search term <strong>{{query}} </strong></p>
{% endif %}
But If I try to add the ptags field within the pagination code by doing &ptags like this:
{% if is_paginated %}
<ul class="pagination pull-right">
{% if page_obj.has_previous %}
<li><i class="fas fa-angle-left"></i>Previous page</li>
{% else %}
<li class="disabled"><span><i class="fas fa-angle-left"></i>Previous page</span></li>
{% endif %}
{% if page_obj.has_next %}
<li>See more results<i class="fas fa-angle-right"></i></li>
{% else %}
<li class="disabled"><span>See more results<i class="fas fa-angle-right"></i></span></li>
{% endif %}
</ul>
{% endif %}
{% else %}
<p> Sorry, no result found for the search term <strong>{{query}} </strong></p>
{% endif %}
I get this error when I go to page 2 and the selected checkboxes filters (ptags) are not following:
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/search/?q=las%20vegas&ptags=&page=2
Raised by: search.views.FacetedSearchView
How can I fix this?
Your template pagination code is removing the extra filter parameters, use this -
In your my_tags.py add this template tag:
#register.simple_tag(name='url_replace')
def url_replace(request, field, value):
d = request.GET.copy()
d[field] = value
return d.urlencode()
paginate as -
{% if is_paginated %}
<br>
<div class="row">
<div class="col-12">
<ul class="pagination float-right">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link" href="?{% url_replace request 'page' page_obj.previous_page_number %}">«</a></li>
{% else %}
<li class="page-item disabled"><span class="page-link">«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active page-item"><span class="page-link">{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li class="page-item"><a class="page-link" href="?{% url_replace request 'page' i %}">{{ i }}</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link" href="?{% url_replace request 'page' page_obj.next_page_number %}">»</a></li>
{% else %}
<li class="page-item disabled"><span class="page-link">»</span></li>
{% endif %}
</ul>
</div>
</div>
{% endif %}
This is the default code for Django pagination:
{% load bootstrap4 %}
{% with bpurl=bootstrap_pagination_url|default:"" %}
<ul class="{{ pagination_css_classes }}">
<li class="prev page-item{% if current_page == 1 %} disabled{% endif %}">
<a class="page-link" href="{% if current_page == 1 %}#{% else %}{% bootstrap_url_replace_param bpurl parameter_name 1 %}{% endif %}">
«
</a>
</li>
{% if pages_back %}
<li class="page-item">
<a class="page-link" href="{% bootstrap_url_replace_param bpurl parameter_name pages_back %}">…</a>
</li>
{% endif %}
{% for p in pages_shown %}
<li class="page-item{% if current_page == p %} active{% endif %}">
<a class="page-link" href="{% if current_page == p %}#{% else %}{% bootstrap_url_replace_param bpurl parameter_name p %}{% endif %}">
{{ p }}
</a>
</li>
{% endfor %}
{% if pages_forward %}
<li class="page-item">
<a class="page-link" href="{% bootstrap_url_replace_param bpurl parameter_name pages_forward %}">…</a>
</li>
{% endif %}
<li class="last page-item{% if current_page == num_pages %} disabled{% endif %}">
<a class="page-link" href="{% if current_page == num_pages %}#{% else %}{% bootstrap_url_replace_param bpurl parameter_name num_pages %}{% endif %}">
»
</a>
</li>
</ul>
{% endwith %}
So, where should I change the code to display less number of pages. The above code was retrieved from the default code of Django-bootstrap4 pagination
Like displaying in this pattern :
I have tried something like this in views.py:
class HomePage(TemplateView):
template_name = "clouderp/index.html"
def get_context_data(self, **kwargs):
context = super(HomePage, self).get_context_data(**kwargs)
qs = Blog.objects.all()
context['blog_list'] = qs
page = self.request.GET.get('page')
paginator = Paginator(qs, 4)
try:
users = paginator.page(page)
except PageNotAnInteger:
users = paginator.page(1)
except EmptyPage:
users = paginator.page(paginator.num_pages)
context['users'] = users
return context
And in template:
{% if users.has_other_pages %}
<ul class="pagination">
{% if users.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in users.paginator.page_range %}
{% if users.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only"></span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if users.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
I have created a blog application using django
I want to show all my blogs in my main index.html page and also wanted to do pagination for the blogs in my index page...
I was wondering how to do it...
Because the process I have done the blogs are not paginated according to 4 at a time...
Please try this code as below:
in views.py code
class BookListView(ListView):
model=Book
paginate_by=10
template_name='book/book_list.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
print (context)
paginator = context['paginator']
page_numbers_range = 10 # Display 5 page numbers
max_index = len(paginator.page_range)
page = self.request.GET.get('page')
print (self.request)
current_page = int(page) if page else 1
start_index = int((current_page - 1) / page_numbers_range) * page_numbers_range
end_index = start_index + page_numbers_range
if end_index >= max_index:
end_index = max_index
page_range = paginator.page_range[start_index:end_index]
context['page_range'] = page_range
return context
book_list = BookListView.as_view()
and the template:
<div class="container">
<!-- Pagination -->
{% if is_paginated %}
<nav>
<ul class="pagination justify-content-center" style="margin:20px 0">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">
<span>Prev</span>
</a>
</li>
{% else %}
<li class="disabled page-item">
<a class="page-link" href="#">
<span>Prev</span>
</a>
</li>
{% endif %}
{% for page in page_range %}
<li {% if page == page_obj.number %} class="active page-item" {% endif %}>
<a class="page-link" href="?page={{ page }}">{{ page }}</a>
</li>
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">
<span>Next</span>
</a>
</li>
{% else %}
<li {% if not page_obj.has_next %}class="disabled page-item"{% endif %}>
<a class="page-link" href="#">
<span>Next</span>
</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>