i know how to implement pagination in class base views using ListView
class ProductListView(ListView):
model = product
template_name = 'products/product_list.html'
context_object_name = 'products'
ordering = ['-pub_date']
paginate_by = 5
but i don't know how to implement paginations in function base views. i read that we have to import Paginator for django.core.paginator and use it in functions base view like this paginator = Paginator(qs, 5) but it's not working.
def Productlistview(request):
qs = product.objects.all()
location_search = request.GET.get('location')
print(location_search)
categories = request.GET.get('categories')
price = request.GET.get('price')
ordering = ['-pub_date']
paginator = Paginator(qs, 5)
if location_search != "" and location_search is not None:
qs = qs.filter(location__contains=location_search)
context = {
'posts': qs
}
return render(request, "products/product_list.html", context)
This is covered in the Pagination section of the documentation. You indeed use a paginator, but you still need to pass the page that you want to show. This is often done through a GET parameter, like for example page. Furthermore you should do the filtering and ordering before paginating.
def product_list_view(request):
qs = product.objects.all()
location_search = request.GET.get('location')
print(location_search)
categories = request.GET.get('categories')
price = request.GET.get('price')
if location_search:
qs = qs.filter(location__contains=location_search)
qs = qs.order_by('-pub_date')
paginator = Paginator(qs, 5)
page = p.page(request.GET.get('page'))
context = {
'posts': page
}
return render(request, "products/product_list.html", context)
Related
So I'm building an e-commerce store with Django(First project after learning). I need to click on Sort in the template, and have the CBV return an object that's ordered by either, price, or whatever field I specify in the request. This is what I have so far
Template
Sort by Lowest Price
View
class ClotheListView(ListView):
model = Clothe
paginate_by = 8
def get_filter_param(self):
# Grab the absolute url and then retrieve the filter param
filter_param = self.request.path.split("/")[-1]
return filter_param
def get_queryset(self):
filter_param = self.get_filter_param()
if(filter_param != ""):
queryset = self.model.objects.filter(cloth_gender=filter_param)
else:
queryset = self.model.objects.all()
return queryset
return clothes_filtered_list.qs
def get_ordering(self):
ordering = self.request.GET.get('ordering', '-cloth_price')
return ordering
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
Url.py
urlpatterns = [
path('', views.ClotheListView.as_view(), name="clothe_list"),
path('<slug:slug>', views.ClotheListView.as_view(),
name="clothe_list_category"),
path('<int:pk>/', views.ClotheDetailView.as_view(), name="clothe_detail")
]
ok, so this is how I did it:
Template
<span class="float-end d-none d-lg-block mt-3">
Sort by: Price -
High To Low |
Price:
Low to High
</span>
View
class ClotheListView(ListView):
model = Clothe
paginate_by = 8
def get_filter_param(self):
# Grab the absolute url and then retrieve the filter param
filter_param = self.request.path.split("/")[-1]
return filter_param
def get_queryset(self):
# code for price sorting
default_order = "cloth_name"
order_param = ""
user_filter = ""
try:
order_param = self.request.GET.get('ordering').strip()
except:
pass
try:
user_filter = self.request.GET.get('filter').strip()
except:
pass
order_by = order_param or default_order
# End of sorting code
filter_param = self.get_filter_param()
if(filter_param != "" or not filter_param):
if(user_filter != ""):
queryset = self.model.objects.filter(
cloth_gender=filter_param, cloth_category=user_filter)
else:
queryset = self.model.objects.filter(
cloth_gender=filter_param)
else:
queryset = self.model.objects.all()
return queryset.order_by(order_by)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context
url.py
urlpatterns = [
path('', views.ClotheListView.as_view(), name="clothe_list"),
path('<slug:slug>', views.ClotheListView.as_view(),
name="clothe_list_category"),
path('<int:pk>/', views.ClotheDetailView.as_view(), name="clothe_detail")
]
I am trying to create an endpoint that returns a list of posts. I want lets say 2 posts per page (for testing only! I know its not that big of a number to cause problem!).
here is my
views.py
class blogsViewSet(ModelViewSet):
queryset = Posts.objects.all()
serializer_class = PostSerializer
pagination_class = pagination.CustomPagination
def list(self, request):
data = request.data
uid = data['uid']
context = {"user": uid}
blogs = Posts.objects.all()
serializer = PostSerializer(blogs, many= True, context= context)
return Response(serializer.data)
here is my
serializers.py
class PostSerializer(ModelSerializer):
isLiked = serializers.SerializerMethodField(method_name='check_react')
totalLikes = serializers.SerializerMethodField(method_name='get_likes')
totalComments = serializers.SerializerMethodField(method_name='get_comments')
def check_react(self, post):
userObj = Users.objects.get(userID = self.context['user'])
#print(type(userObj))
if Likes.objects.filter(postID = post, userID = userObj).exists():
isLiked = Likes.objects.get(postID = post, userID = userObj)
likeObj = LikeSerializer(isLiked)
#print('isLiked: ', likeObj.data['isLiked'])
return (likeObj.data['isLiked'])
return(False)
#print(isLiked)
def get_likes(self, post):
count = Likes.objects.filter(postID = post).count()
return count
def get_comments(self, post):
count = PostsComments.objects.filter(postID = post).count()
return count
class Meta:
model = Posts
fields = '__all__'
and, here is my
pagination.py,
from rest_framework import pagination
class CustomPagination(pagination.PageNumberPagination):
page_size = 2
page_size_query_param = 'page_size'
max_page_size = 3
page_query_param = 'p'
I am importing this class on views.py and it works as expected when I try to retrieve a list of users via userMVS
class userMVS(ModelViewSet):
queryset = Users.objects.all()
serializer_class = UserSerializer
pagination_class = pagination.CustomPagination
You must write your list function of views as -
def list(self, request, *args, **kwargs):
queryset = Posts.objects.all()
paginatedResult = self.paginate_queryset(queryset)
serializer = self.get_serializer(paginatedResult, many=True)
return Response(serializer.data)
Edits -
Suppose this is my pagination class -
class CustomPagination(PageNumberPagination):
page_size = 8
page_query_param = "pageNumber"
and used in this way at class level and mentioned above at list function -
class blogsViewSet(ModelViewSet):
queryset = Posts.objects.all()
serializer_class = PostSerializer
pagination_class = CustomPagination
then this is the url that should work
http://localhost:8000/urlofpostviewset/?pageNumber=passThePageNumber
Do read from the documents all the properties you use at CustomPagination class.
Can't pass extra variable with listview
I tried adding another function and returning the value but it then doesn't return the main part.
class PostListView(ListView):
model = Post
template_name = 'blog/home.html' # <app>/<model>_<viewtype>.html
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 3
def get_context_data(self, **kwargs):
posting = []
for post in Post.objects.all():
post_words = post.content.split()
for word in post_words:
posting.append(word.lower())
mostused_word = []
for word in posting:
if len(mostused_word) == 0:
mostused_word.append({'daword': word, 'word_count': posting.count(word)})
else:
if posting.count(word) > mostused_word[0]['word_count']:
mostused_word[0] = {'daword': word, 'word_count': posting.count(word)}
context = {
'mostused_word': mostused_word[0]['daword'],
'mostused_word_count': mostused_word[0]['word_count'],
'postin': posting,
}
return context
I expect to pass both needed variables, not only one of them.
You need to call the super method.
def get_context_data(self, **kwargs):
...
context = {
'mostused_word': mostused_word[0]['daword'],
'mostused_word_count': mostused_word[0]['word_count'],
'postin': posting,
}
kwargs.update(context)
return super().get_context_data(**kwargs)
I have this ListView and i am trying to get only 12 cars from my db, and order them by price, i have 20 entries in my db and in the buttons of pagination it shows 6 buttons, aka 6 pages, so it is returning all possible data from db, at this point I am lost and can't find the bug, any help would be very much appreciated for both, pagination and ordering.
class CardListView(ListView):
model = Car
template_name = 'home.html'
context_object_name = 'cars'
ordering = ['-price']
paginate_by = 5
limit = 12
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
paginator = context['paginator']
page_numbers_range = 10
max_index = len(paginator.page_range)
page = self.request.GET.get('page')
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]
cars = Car.objects.all()[:self.limit]
car_types = CarCategory.objects.all()
context['cars'] = cars
context['car_types'] = car_types
context['page_range'] = page_range
return context
You do not need to do the pagination logic by yourself, you only should implement in the get_context_data the additional elements you want to pass to the template. The pagination logic is handled by the ListView itself. If you want to limit the queryset, you should do that in the get_queryset(..) [Django-doc] function:
class CardListView(ListView):
model = Car
template_name = 'home.html'
context_object_name = 'cars'
ordering = ['-price']
paginate_by = 5
limit = 12
def get_queryset(self):
return super().get_queryset()[:self.limit]
def get_context_data(self, **kwargs):
context = super().get_context_data() # with paginated queryset
context['car_types'] = car_types = CarCategory.objects.all()
return context
The original ListView implementation will call the get_queryset, and then pass it to the proper paginator. By using super() we furthermore do not need to care about the ordering, etc. These are all handled by the ListView itself.
I am attempting to make my API get return a maximum of 10 per page. This helps me with infinite loading. The API url will be I am trying looks like this:
www.mysite.com/api/test/?user=5&page=1
However, this does not work.
I've followed the official docs here without success.
I have only modified two files, settings.py & rest_views.py.
settings.py-
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}
rest_views.py-
from django.core.paginator import Paginator
...
wardrobematch = {
'user': lambda x: ('user__pk', x)
}
class WardrobeListView(APIView):
renderer_classes = (JSONRenderer, )
paginate_by = 10
paginate_by_param = 'page_size'
max_paginate_by = 100
def get(self, request, *args, **kwargs):
filters = {}
for key, value in request.GET.items():
key = key.lower()
if key in wardrobematch:
lookup, val = wardrobematch[key](value.lower())
filters[lookup] = val
qset = (
Analytic.objects
.filter(like=True,**filters)
.order_by('-updated',)
# .distinct('product_id',)
.values('product_id', 'product__name', 'product__brand', 'product__store__store_name', 'product__variation__image__image', 'product__variation__price__price',)
)
return Response(qset)
When using regular ApiView, you should call the pagination API yourself, it will not perform pagination automatically.
I have created a pagination and a serializer mixim. I'm not sure it is best method, but it worked for me.
class SerializerMixim(object):
def serialize_object(self,obj):
"""Serilize only needed fields"""
return NotImplementedError
class PaginationMixim(object):
_serializer = None
def paginate(self,queryset,num=10):
page = self.request.GET.get('page')
paginator = Paginator(queryset, num)
try:
queryset = paginator.page(page)
except PageNotAnInteger:
queryset = paginator.page(1)
except EmptyPage:
queryset = paginator.page(paginator.num_pages)
count = paginator.count
previous = None if not queryset.has_previous() else queryset.previous_page_number()
next = None if not queryset.has_next() else queryset.next_page_number()
if self._serializer:
objects = self._serializer(queryset.object_list,many=True).data
else:
objects = [self.serialize_object(i) for i in queryset.object_list]
data = {'count':count,'previous':previous,
'next':next,'object_list':objects}
return Response(data)
def serialize_object(self,obj):
return {'id':obj.pk}
class WardrobeListView(APIView,PaginationMixim,SerializerMixim):
renderer_classes = (JSONRenderer, )
#_serializer = AnalyticSerializer
def get(self, request, *args, **kwargs):
filters = {}
for key, value in request.GET.items():
key = key.lower()
if key in wardrobematch:
lookup, val = wardrobematch[key](value.lower())
filters[lookup] = val
qset = (
Analytic.objects
.filter(like=True,**filters)
.order_by('-updated',)
# .distinct('product_id',)
return self.paginate(qset)
def serialize_object(self,obj):
return obj.serilized
then you need to create a propery for Analytic model like,
class Analytic(models.Model):
.....
#property
def serilized(self):
summary = {
'id':self.product.id,
'image':self.product.name,
.......
}
return summary
this will also work with django rest serializers
I got your first example working- to me it was clearer and more basic. All I did was add ".object_list" to stop the "is not JSON serializable" error.
This is your answer with my tiny tweak:
class WardrobeListView(APIView):
renderer_classes = (JSONRenderer, )
def get(self, request, *args, **kwargs):
filters = {}
for key, value in request.GET.items():
key = key.lower()
if key in wardrobematch:
lookup, val = wardrobematch[key](value.lower())
filters[lookup] = val
qset = (
Analytic.objects
.filter(like=True,**filters)
.order_by('-updated',)
# .distinct('product_id',)
.values('product_id', 'product__name', 'product__brand', 'product__store__store_name', 'product__variation__image__image', 'product__variation__price__price',)
)
paginator = Paginator(qset, 2) # Show 25 items per page
page = request.GET.get('page')
try:
qset = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
qset = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
qset = paginator.page(paginator.num_pages)
return Response(qset.object_list)