How does django's pagination work in a django view [duplicate] - python

This question already has answers here:
Django lazy QuerySet and pagination
(2 answers)
Closed 7 years ago.
So I was reading about pagination, I have done it quite a few times writing this app but I was wondering how does pagination in django work at sql level.
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
def listing(request):
contact_list = Contacts.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page
page = request.GET.get('page')
try:
contacts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
contacts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
contacts = paginator.page(paginator.num_pages)
return render_to_response('list.html', {"contacts": contacts})
Does Contacts.objects.all() get called evertime I am hitting the view ?
Or does Paginator maintains a state somehow ? What would the sql query look like for paginator = Paginator(contact_list, 25) Are there generators being used behind the scenes and things are lazily evaluated?
Sorry if this is a dumb question, there is a lot of abstraction in Django and I seem to miss all the action behind.
Thanks in advance

I am posting this duplicate link as answer, because title of your question is very readable and there is answer for all your question
Django lazy QuerySet and pagination

Related

Django Pagination not work in the next page

I'm building an application that allows to page the result of a search. The results can be numerous that's why I used django's pagination. I have configured filters and sorting of results displayed by 10:
`
def search_details(request, type_anc):
querylist = Annonce.objects.filter(type_annonce = type_anc, is_published=True)
...........
paginator = Paginator(querylist, 10)
page = request.GET.get('page')
paged_listings = paginator.get_page(page)
`
When I click on the button that sends me to the next page, 'order_by' is not respected.
For example I have a result that sorts the price by descending order and the last element is 850 000, in the next page the prices displayed should be below 850 000.
Can you help me?
Actually, this question seems to be unclear but I framed my answer according to the details provided. (Please provide a meaningful problem statement, need modal and template details also to provide a solution...)
Here Your modal name is Announce, you need to paginate by 10 and it's a search function. here I assume your template name to be 'XYZ.html' so views gonna be
views.py
from django.core.paginator import Paginator
from django.shortcuts import render
from .moddels import Announce
def search_details(request, type_anc):
announce_list = Announce.objects.filter(type_annonce=type_anc, is_published=True)
paginator = Paginator(announce_list, 10)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(resuest, 'XYZ.html', {'page_obj': page_obj})
Here page_obj holds the data for the page that which user requests... you can render the data in the template by following the Django docs.Here is the link https://docs.djangoproject.com/en/4.1/topics/pagination/#:~:text=%7B%25%20for%20contact,%3C/div%3E

Why does my django pagination keeps returning the same items infinitely?

I am using django and ajax to create a infinite scroll on my website. I would like it to load more items from the database (that are in the next page) when the user scrolls to the bottom of the page. Everything is working perfectly except that it keeps returning the first page's items infinitely. For example if a user scrolls down to the end of a page instead of adding page 2's elements it just add the same elements from the first page to the bottom again. I am very sure this issue is from my views.py. I can't seem to figure out what's wrong.
def feed(request):
queryset2 = Store_detail.objects.filter(store_lat__gte=lat1, store_lat__lte=lat2)\
.filter(store_lng__gte=lng1, store_lng__lte=lng2)
queryset3 = Paginator(queryset2, 4)
page = request.GET.get('page',1)
try:
queryset = queryset3.page(1)
except PageNotAnInteger:
queryset = queryset3.page(page)
except EmptyPage:
queryset = ""
context = {
"location":location,
"queryset":queryset,
}
# return HttpResponse(template.render(context,request))
return render(request, 'main/feed.html', {'queryset': queryset,
'location':location,})
So basically I would like to load the next page when a user scrolls to the end of the screen and if there are no more items in the next page or the next page does not exist then stop adding items.
The pagination logic is a bit off. You paginate with:
try:
# you first try to retrieve page 1
queryset = queryset3.page(1)
except PageNotAnInteger:
queryset = queryset3.page(page)
except EmptyPage:
queryset = ""
This thus means that you first aim to fetch the first page, and only if 1 is not an integer, you will fetch a page with the page querystring parameter. You should swap these, like:
try:
queryset = queryset3.page(page)
except PageNotAnInteger:
queryset = queryset3.page(1)
except EmptyPage:
queryset = Store_detail.objects.none()

How to implement pagination in a Django and React app without using the REST framework?

I am working on a website whose back-end is in Django and front-end is developed using React. I want to add the pagination feature in the website but don't know how it will be implemented in the frontend part.
I want to send the total page count to the react app.
I have written the following code in my views function till now
def index(request):
influencers = Influencer.objects.all()
paginator = Paginator(influencers,16)
page = request.GET.get('page')
paged_listings = paginator.get_page(page)
user_list = UserList.objects.all().filter(user_id = request.user.id)
queryset = list(chain(paged_listings,user_list),paginator.count)
ser_query = serializers.serialize('json', queryset)
return HttpResponse(ser_query)
Also I am not using REST framework to develop the back-end site.
I want to know what information I have to send to the React front-end site for this to work. How should I proceed?
I'd recommend you do use django-rest-framework because it's probably easier with pagination.
However, if you want to avoid that you could pass your own structure (obviously, you may need to pass other information such as next page/previous page etc).
The challenge here is ensuring everything is JSON serializable - that means for Queryset you have to use .values() and wrap the result with list(). For Paginator you need to wrap with list().
from django.http.response import JsonResponse
def index(request):
influencers = Influencer.objects.all().values()
paginator = Paginator(influencers,16)
page = request.GET.get('page')
paged_listings = paginator.get_page(page)
user_list = UserList.objects.all().filter(user_id = request.user.id).values()
queryset = list(chain(paged_listings,user_list),paginator.count)
content = {'total_page_count': paginator.num_pages, 'data': queryset}
return JsonResponse(content)

Django Select Related in Template Paginated Search Results to Reduce Queries?

I have a model (products) which is actually containing a number of many-to-many fields.
Ideally I am trying to reduce queries to the number of products themselves -- 25, but considering the depth of foreignkeys and m2ms, I understand this might not be possible. But still I'm shooting for best results.
Here is my view:
def index(request):
products = Product.objects.select_related()
paginator = Paginator(products, 25)
page = request.GET.get('page')
try:
products = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
products = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
products = paginator.page(paginator.num_pages)
print (len(connection.queries))
return render(request, 'editor-index.html', {
'products': products,
'connection':connection,
'csrf':csrf(request)
})
How can I reduce the queries in this? It would be best to prefetch all data related to the product. Is such a thing possible?
select_related only works for foreign keys. For many to many fields you can use prefetch_related. I think that with prefect related you have to specify the related models you want to fetch, and that you can't call it with no arguments like select_related.
Note that you shouldn't need 25 queries for 25 products. It should be possible to reduce it to one query for the products queryset, one additional query for each prefetch_related argument, and (because you are using a paginator) one for the total number of objects.

Django Pagination

I need to make real pagination instead of paginating on all retreived data. The example in Django documentation site, is like;
def listing(request):
contact_list = Contacts.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page
page = request.GET.get('page')
try:
contacts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
contacts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
contacts = paginator.page(paginator.num_pages)
return render_to_response('list.html', {"contacts": contacts})
This code is paginating records on all retreived records. But there is a trouble. Trying to retreive all record takes many time if there are so many records. I need a solution to retrieve the records page by page from database.
Is there another solution to do this in Django?
You make a false assumption. Django does not retrieve all objects when paginating: it slices the queryset appropriately, which uses LIMIT and COUNT on the SQL.
A QuerySet is a lazy object. When you assign contact_list = Contacts.objects.all(), Django will NOT hit the database. Until you call the methods such as count(), filter(), first(),..., or contact_list[1:5], Django will really retrieve data from the database. SQL statements that Django generate will correlate to each method and these SQL statments will be sent to the DB.
E.g: contact_list[1:5] generate a SQL statement have LIMIT and OFFSET clauses.
In Paginator class, the QuerySet will passed to the its constructor
paginator = Paginator(contact_list, 25)
When you call paginator.page(page), the statement is called:
return self._get_page(self.object_list[bottom:top], number, self)
Look inside Paginator class (django/core/paginator.py), it fetches only required pages. There is only one problem on big tables: if you want to show total page numbers you must make count(*) on entire table which can took a long time in some databases (i.e. postgresql, mysql with innodb).
BTW, try to use generic views in django, ListView would be fine here.
Here we using get_page() to get page wise data(1 page contain 25 data).I would suggest for this like :
def listing(request):
contact_list = Contacts.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page
page = request.GET.get('page')
contacts = paginator.get_page(page)
return render_to_response('list.html', {"contacts": contacts})

Categories

Resources