7👍
Typically, to preserve GET parameters you simply re-write them manually. There shouldn’t be many cases where having to do this will matter.
&page={{page}}&total={{total}}
You can abstract this away into a template include or a custom template tag.
https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/
Additionally, you could create a string filter that takes URL params as a string as well as a dict of values you want to change. The filter could then parse the params string, update the value, then recombine the string back into URL params.
{{ request.get_full_path | update_param:'page=8' }}
15👍
The generic solution is to define a “custom template tag” (a function) which keeps the complete URL but updates the GET parameters you pass to it.
After registration, you can use this function in your templates:
<a href="?{% query_transform page=contacts.previous_page_number %}">previous</a>
To define and register the custom template tag, include this code in a python file:
from django import template
register = template.Library()
@register.simple_tag(takes_context=True)
def query_transform(context, **kwargs):
query = context['request'].GET.copy()
for k, v in kwargs.items():
query[k] = v
return query.urlencode()
*Thanks to Ben for the query_transform code. This is an adapation for python 3 from his code.
Why this method is better than reconstructing the URLs manually:
If you later decide that you need additional parameters in your URLs: 1. you don’t have to update all the links in your templates. 2. You don’t need to pass all the params required for recostructing the URL to the templates.
1👍
Subclassing
I solved this problem by subclassing Django’s Paginator class and adding the stuff I needed there.
You need to override the init method to allow yourself to pass the request and form objects from the view, so that you can retrieve the request.GET parameters and compare them to form.fields. You want to only allow GET parameter names that are predefined in your form. Otherwise you remove them.
Once you have subclassed the Pagination class, you can use it in your views.py files, passing the extra request and form parameters to it. Then you can render your template as suggested in the Django documentation, but now you have access to the paginator.first_params, paginator.last_params, page.previous_params, and page.next_params variables that you can use.
pagination.py
import urllib
from django.core.paginator import Paginator as DjangoPaginator, EmptyPage
class Paginator(DjangoPaginator):
def __init__(self, *args, **kwargs):
request = kwargs.pop('request', None)
form = kwargs.pop('form', None)
super().__init__(*args, **kwargs)
self.params = {key: value for key, value in request.GET.items() if key in form.fields.keys()}
self.first_params = urllib.parse.urlencode({**self.params, 'page': 1})
self.last_params = urllib.parse.urlencode({**self.params, 'page': self.num_pages})
def get_page(self, *args, **kwargs):
page = super().get_page(*args, **kwargs)
try:
page.previous_page_number = page.previous_page_number()
except EmptyPage:
page.previous_page_number = None
try:
page.next_page_number = page.next_page_number()
except EmptyPage:
page.next_page_number = None
page.previous_params = urllib.parse.urlencode({**self.params, 'page': page.previous_page_number})
page.next_params = urllib.parse.urlencode({**self.params, 'page': page.next_page_number})
return page
views.py
from .pagination import Paginator
paginator = Paginator(queryset, per_page, request=request, form=form)
page = paginator.get_page(page_number)
pagination.html
{% if page %}
<nav id="pagination">
{% if page.has_previous %}
<a href="?{{ paginator.first_params }}">« First</a>
<a href="?{{ page.previous_params }}" rel="prev">Previous</a>
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages }}.
</span>
{% if page.has_next %}
<a href="?{{ page.next_params }}" rel="next">Next</a>
<a href="?{{ paginator.last_params }}">Last »</a>
{% endif %}
</nav>
{% endif %}
- Python/Django: sending emails in the background
- 'QuerySet' object has no attribute ERROR, trying to get related data on ManyToMany fields
- Why use Django's collectstatic instead of just serving the files directly from your static directory?
- Registering Django system checks in AppConfig's ready() method
- Django forms give: Select a valid choice. That choice is not one of the available choices
0👍
This is what I did and find easier. Many not be better approach though!
param = ""
if search_programs:
qs = qs.filter(title__icontains=search_programs)
param = param + f"&search_programs={search_programs}"
if level:
qs = qs.filter(level__icontains=level)
param = param + f"&level={level}"
if category:
qs = qs.filter(sector__icontains=category)
param = param + f"&category={category}"
paginator = Paginator(qs, 16)
page_number = self.request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'page_obj': page_obj,
"param": param
}
return render(self.request, self.template_name, context)
# in html
<a href="?page={{ page_obj.next_page_number }}{{param}}" class="page-link">next</a>
- 'Questions ' object is not iterable Django
- Django 1.6 and django-registration: built-in authentication views not picked up
- Django is very slow on my machine
- What is the difference between the create and perform_create methods in Django rest-auth