I'm applying pagination on my sports.html page. In views.py I'm using ListView and using paginate_by = 2 but issue is pagination is not taking effect on webpage.
Pagination numbers are visible on page and when clicking on those page numbers it's not showing any error but all posts are visible on all pages, posts are not divided by paginate_by value.
Can anyone point out what I'm doing wrong here ?
views.py
class SportsList(ListView):
model = Sports
template_name = 'frontend/sports.html'
paginate_by = 2
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['main'] = Main.objects.all()
context['sports'] = Sports.objects.all()
return context
sports.html
<section class="blog_area">
<div class="container">
<div class="row">
<div class="col-lg-8">
<div class="blog_left_sidebar">
{% for sport in sports %}
<article class="row blog_item">
<div class="col-md-3">
<div class="blog_info text-right">
<ul class="blog_meta list">
<li>XAR<i class="lnr lnr-user"></i></li>
<li>From: {{ sport.from_date }}<i class="lnr lnr-calendar-full"></i></li>
<li>To: {{ sport.to_date }}<i class="lnr lnr-calendar-full"></i></li>
<li>{{ sport.category }}<i class="lnr lnr-layers"></i></li>
</ul>
</div>
</div>
<div class="col-md-9">
<div class="blog_post">
<img src="{{ sport.featured_image.url }}" alt="">
<div class="blog_details">
<a href="{% url 'sports_details' sport.slug %}">
<h2>{{ sport.title }}</h2>
</a>
<p>{{ sport.content|truncatewords:30|safe }}</p>
View More
</div>
</div>
</div>
</article>
{% endfor %}
{% if is_paginated %}
<nav class="blog-pagination justify-content-center d-flex">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item">
<a href="?page={{ page_obj.previous_page_number }}" class="page-link">
<span aria-hidden="true">
<span class="lnr lnr-chevron-left"></span>
</span>
</a>
</li>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<li class="page-item active">{{ num }}</li>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<li class="page-item">{{ num }}</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a href="?page={{ page_obj.next_page_number }}" class="page-link" aria-label="Next">
<span aria-hidden="true">
<span class="lnr lnr-chevron-right"></span>
</span>
</a>
</li>
{% endif %}
</ul>
{% endif %}
</nav>
</div>
</div>
</div>
</div>
</section>
This is because you are creating your queryset on get_context_data. You are not respecting the listview structure. Try something like this on your view:
class SportsList(ListView):
queryset = Sport.objects.all()
context_object_name = “sports”
template_name = 'frontend/sports.html'
paginate_by = 2
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['main'] = Main.objects.all()
return context
You need to use the following in the views.py.
context_object_name = 'sports'
By default, While a Django view is executing, self.object_list will contain the list of objects (usually, but not necessarily a queryset) that the view is operating upon. You can see the reference in Django doc here.
generic list view
Of course, you are adding 'sports' in the context of def get_context_data but a Django generic list view need to get operated upon the value mentioned in context_object_name or the object_list.
Hence in your views.py use:
class SportsList(ListView):
model = Sports
template_name = 'frontend/sports.html'
paginate_by = 2
context_object_name = 'sports'
ordering = ["id"]
Related
I am having a problem in categorize Posts. I have categories in Post Model, Please help me solve this issue!
MODELS.PY
html= "html"
css= "css"
python= "python"
javascript = "javascript"
Lang=(
(html,"HTML"),
(css,"CSS"),
(python,"PYTHON"),
(javascript,"JAVASCRIPT")
)
Broilerplate = "Broilerplate"
Simple_Tags = "Simple Tags"
Elements = "Elements"
Webpages = "Webpages"
Category = (
(Broilerplate,"BROILERPLATE"),
(Simple_Tags,"Simple tags"),
(Elements,"Elements"),
(Webpages,"Webpages")
)
class Post(models.Model):
title = models.CharField(max_length=75)
subtitle = models.CharField(max_length=150)
language_1 = models.CharField(max_length=100, choices=Lang, default=html)
content_1= models.TextField(blank=True)
language_2 = models.CharField(max_length=100, choices=Lang,blank=True)
content_2= models.TextField(blank=True)
language_3 = models.CharField(max_length=100, choices=Lang,blank=True)
content_3= models.TextField(blank=True)
language_4 = models.CharField(max_length=100, choices=Lang,blank=True)
content_4= models.TextField(blank=True)
language_5 = models.CharField(max_length=100, choices=Lang,blank=True)
content_5= models.TextField(blank=True)
category= models.CharField(max_length=100, choices=Category, default=Broilerplate)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User,on_delete=models.CASCADE)
def __str__(self):
return self.title
# def update(self):
# updated_at = timezone.now()
# self.save(updated_at)
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk':self.pk})
VIEWS.PY
def search_by_category(request, category):
if request.post.objects.filter(pk=request.post.id).first().category == 'Broilerplate':
nor = request.post.objects.filter(pk=request.post.id).first().category
print(nor)
posts = Post.objects.filter(category='Broilerplate')
category = posts.first().category
print(category)
context = {'posts': posts, 'title': category , 'category': category}
return render(request, 'category.html', context)
else:
context = {'title': category , 'category': category}
return render(request, 'category.html', context)
URLS.PY
urlpatterns = [
path('html/',PostListView.as_view(), name='CodeWriter_Homepage'),
path('python/',views.CodeWriter_homepage_python, name='CodeWriter_Homepage_python'),
path('search/', views.search, name='search'),
path('categroize-by/<str:category>/', views.search_by_category, name='search_by_category'),
path('post-details/<int:pk>/',PostDetailView.as_view(), name='Post_details_page'),
path('post-update/<int:pk>/',PostUpdateView.as_view(), name='Post_update_page'),
path('post-delete/<int:pk>/',PostDeleteView.as_view(), name='Post_delete_page'),
path('user/<str:username>/', UserPostListView.as_view(), name='user-post'),
path('new-post/',PostCreateView.as_view(), name='New-post_page')
]
CATEGORY.html
How can I get the data of the post category in views.py?That will help me very much!
{% block main_post_body %}
<main class="post-body normal" >
<p class="post-heading"> Post for <b>{{ category }}</b> :</p>
{% comment %} <h1 class="mb-3">Search results for <b>{{category}}</b>: </h1> {% endcomment %}
{% comment %} {% if posts|length < 1 %}
<h3>No search results found</h3>
<p>Your search results for <b>{{ query }}</b> is not found.</p>
{% endif %} {% endcomment %}
{% for post in posts %}
<div class="row">
<div class="col span-8-of-12 card">
<div class="row">
<!-- <div class="triangle"></div>
<div class="person-info-card">
<div class="row">
<div class="col"><img src="{% static 'resoures/css/img/Me.jpg' %}" alt=""></div>
<div class="col">
<p>Ketan Vishwakarma</p>
<p class="post-no">126 Posts | 1k Followers</p>
</div>
</div>
</div> -->
<div class="col span-1-of-12">
<div class="person-img" id="person-info-card-toggle">
<img src="{{ post.author.profile.image.url }}" alt="" />
</div>
</div>
<div class="col span-7-of-12">
<h3>{{ post.title }} </h3>
<h4>{{ post.subtitle }}</h4>
</div>
<div class="col span-1-of-12">
<span class="ion-md-heart-empty"></span>
</div>
<div class="col span-1-of-12">
<span class="ion-md-add-circle-outline"></span>
</div>
<div class="col span-1-of-12 share">
<span class="ion-md-share"></span>
<ul class="dropdown-list-share">
<li><span class="ion-md-copy"> Copy</span></li>
<li><span class="ion-logo-whatsapp"> Share on Whatsapp</span></li>
<li><span class="ion-logo-facebook"> Share on facebook</span></li>
<li><span class="ion-md-more"> More</span></li>
</ul>
</div>
<div class="col span-1-of-12">
<span class="ion-md-menu"></span>
<ul class="dropdown-list">
<li>Doesn't work</li>
<li>Report</li>
<li>Report</li>
</ul>
</div>
</div>
<div class="tabs">
<ul class="tabs-list">
<li class="active">{{ post.language_1 }}</li>
{% if post.content_2 == "" %}
{% else %}
<li class="not-clickable hint--info" aria-label="To view this click Read more">{{ post.language_2 }}</li>
{% endif %}
{% if post.content_3 == "" %}
{% else %}
<li class="not-clickable hint--info" aria-label="To view this click Read more">{{ post.language_3 }}</li>
{% endif %}
{% if post.content_4 == "" %}
{% else %}
<li class="not-clickable hint--info" aria-label="To view this click Read more">{{ post.language_4 }}</li>
{% endif %}
{% if post.content_5 == "" %}
{% else %}
<li class="not-clickable hint--info" aria-label="To view this click Read more">{{ post.language_5 }}</li>
{% endif %}
<ul class="categories">
<abbr title="Categiores">
<a href="">
<span class="ion-md-code-working"></span>
{{ post.category }}
</a>
</abbr>
<!-- <li>Broilerplate</li> -->
</ul>
</ul>
<div id="tab1" class="tab active">
<p>
<pre><code class="language-{{ post.language_1 }}">
{{ post.content_1 }}
</code></pre>
</p>
</div>
<div id="tab2" class="tab">
<p>
<pre><code class="language-{{ post.language_2 }}">
{{ post.content_2 }}
</code></pre>
</p>
</div>
<div id="tab3" class="tab">
<p>
<pre><code class="language-{{ post.language_3 }}">
{{ post.content_3 }}
</code></pre>
</p>
</div>
<div id="tab4" class="tab">
<p>
<pre><code class="language-{{ post.language_4 }}">
{{ post.content_4 }}
</code></pre>
</p>
</div>
<div id="tab5" class="tab">
<p>
<pre><code class="language-{{ post.language_5 }}">
{{ post.content_5 }}
</code></pre>
</p>
</div>
</div>
<span class="ion-md-arrow-round-down"> Read More</span>
<h6>{{ post.date_posted|date:"F d, Y" }}</h6>
</div>
<div class="col span-4-of-12 main-card ">
<div class="card-small">
<h1>Result: </h1>
<div class="result-box">
<iframe src="" frameborder="0">just for fun</iframe>
</div>
<h6>{{ post.date_posted|date:"F d, Y" }}</</h6>
</div>
</div>
</div>
{% endfor %}
</main>
{% if is_paginated %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info mb-4" href="?page=1">First</a>
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.previous_page_number }}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-info mb-4" href="?page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="btn btn-outline-info mb-4" href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
{% endif %}
{% endblock main_post_body %}
NoteI have registered the Post model in admin.py
Tell me the solution to this problem I cannot get the solution I have been trying it for so long and am stuck on this.
I am at the beginner level in the Django Framework. The queryset works well in my post list. But I face a problem in pagination to the second page queryset according to the tag field in my blog post list. When I go to the second page it shows the main list of the second page, not queryset page. I don't know where the problem behind the seen...
models.py code
class Post(models.Model):
TOPICS = (
('Programming' , 'Programming'),
('C' , 'C'),
('C++' , 'C++'),
('Java' , 'Java'),
('Python' , 'Python'),
)
title = models.CharField(max_length=100, blank=False, null=False)
content = models.TextField()
tag = models.CharField(max_length=50, choices=TOPICS, blank=False, null=False, default='Programming')
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
#redirect to post_detail when some post a blog
def get_absolute_url(self):
return reverse('post_detail', kwargs={'pk':self.pk})
viwes.py code
from django.core.paginator import Paginator
from .filters import BlogFilter
def home(request):
posts = Post.objects.all().order_by('-date_posted')
postFilter = BlogFilter(request.GET, queryset=posts)
posts = postFilter.qs
paginator = Paginator(posts, 3)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
context = {
'page_obj' : page_obj,
'postFilter' : postFilter,
}
return render(request, 'blog/index.html', context)
template code
{% extends 'blog/base.html'%}
{% load crispy_forms_tags %}
{% load static %}
{% block content %}
<section id="article">
<div class="container">
<div class="row mt-4">
<div class="col-md-8 m-auto">
<form method="get">
{{postFilter.form|crispy}}
<button class="btn btn-primary" type="submit">Search</button>
</form>
{% for i in page_obj %}
<article class="media content-section">
<a href="{% url 'user_posts' i.author.username %}">
<img class="rounded-circle article-img" src="{{i.author.profile.image.url}}" alt="">
</a>
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="{% url 'user_posts' i.author.username %}">{{ i.author }}</a>
<small class="text-muted">{{i.date_posted|date:"F d, Y"}}</small>
</div>
<h2><a class="article-title" href="{% url 'post_detail' i.id %}">{{i.title}}</a></h2>
<p class="article-content">{{i.content|linebreaks|truncatewords:50}}</p>
</div>
</article>
{% endfor %}
{% if page_obj.has_previous %}
<a class="btn btn-outline-info mb-4" href="?page=1">First</a>
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.previous_page_number}}">Previous</a>
{% endif %}
{% for num in page_obj.paginator.page_range %}
{% if page_obj.number == num %}
<a class="btn btn-info mb-4" href="?page={{ num }}">{{ num }}</a>
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
<a class="btn btn-outline-info mb-4" href="?page={{ num }}">{{ num }}</a>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.next_page_number }}">Next</a>
<a class="btn btn-outline-info mb-4" href="?page={{ page_obj.paginator.num_pages }}">Last</a>
{% endif %}
</div>
</div>
</div>
</section>
{% endblock %}
I'm trying to paginate, it shows in the address bar that I'm on page 2 but nothing new gets displayed.
Below is an excerpt from my views.py looks:
class JobList(ListView):
model = Job
template_name = "jobs/job_listings.html"
context_object_name = "job_list"
ordering = ['-published_date']
paginate_by = 3
def get_context_data(self, **kwargs):
context = super(JobList, self).get_context_data(**kwargs)
jobs_expiring_soon = Job.objects.filter(application_last_date__gte=datetime.now(), application_last_date__lte=lookup_date)
state_list = State.objects.order_by('name')
profession_list = Profession.objects.order_by('name')
context['jobs_expiring_soon'] = jobs_expiring_soon
context['state_list'] = state_list
context['profession_list'] = profession_list
return context
Below is an excerpt from my urls.py file:
path('', JobList.as_view(), name = 'job-list'),
Below is the associated template:
{% extends 'base.html' %}
{% block page_content %}
{% for job in job_list %}
<div class="listing-wrapper">
<div class="listing-container border-top border-bottom">
<a href="{{ job.get_absolute_url }}">
<h2 class="heading mt-3 mb-1 mx-2 d-inline-block">{{ job.title|truncatechars:75 }}</h2>
<p class="mx-2"><span class="sub-heading mr-1">Number of Posts:</span><span class="mr-1 ml-1">{{ job.nop }}</span>|<span class="sub-heading ml-1 mr-1">Last Date to Apply:</span><span>{{ job.application_last_date|date:"j-M-Y" }}</span></p>
<p class="mx-2 mb-3">{{ job.summary|truncatechars:200 }}</p>
</a>
</div>
</div>
{% endfor %}
{% if is_paginated %}
<ul class="pagination justify-content-center my-4">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link bg-dark text-white" href="?page{{ page_obj.previous_page_number }}">← Previous Page</a>
</li>
{% endif %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link bg-dark text-white" href="?page{{ page_obj.next_page_number }}">Next Page →</a>
</li>
{% endif %}
</ul>
{% endif %}
{% endblock page_content %}
I would really grateful, if anyone could please help me in getting this fixed. Thanks in advance!
Try setting context_object_name = 'job'. I believe _list gets appended to it automatically which would mean your current view generates the context job_list_list.
I find myself repeatedly cycling through the same set of data, accessing database several time for the same loops to achieve displaying the correct data on one template, here's the code:
<!-- item images and thumbnails -->
<div class="row">
<div class="col-12 col-sm-8">
<div id="item{{item.pk}}Carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
{% for image in item.itemimage_set.all %}
<li data-target="#item{{item.pk}}Carousel" data-slide-to="{{forloop.counter0}}"
{% if forloop.first %} class="active" {% endif %}></li>
{% endfor %}
</ol>
<div class="carousel-inner shadow-lg rounded-sm">
{% for image in item.itemimage_set.all %}
<div class="carousel-item {% if forloop.first %} active {% endif %}">
<img src="{{image.image.url}}" class="d-block w-100" alt="...">
</div>
{% endfor %}
</div>
{% if item.itemimage_set.count > 1 %}
<a class="carousel-control-prev" href="#item{{item.pk}}Carousel" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#item{{item.pk}}Carousel" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
{% endif %}
</div>
</div>
<div class="pl-sm-0 col-12 col-sm-4 d-flex flex-wrap align-content-start">
{% for image in item.itemimage_set.all %}
<div class="col-4
{% if item.itemimage_set.count > 3 %}
col-sm-6
{% else %}
col-sm-8
{% endif %}
mt-2 px-1 mt-sm-0 pb-sm-2 pt-sm-0 mb-0">
<img src="{{image.image.url}}" alt="" class="col-12 p-0 rounded-sm shadow-sm"
data-target="#item{{item.pk}}Carousel" data-slide-to="{{forloop.counter0}}">
</div>
{% endfor %}
</div>
</div>
<!-- /item images and thumbnails -->
The above code renders the item's itemimage bootstrap carousel and on the same page, an extra carousel modal:
<!-- itemImageModal -->
<div class="modal fade" id="itemImageModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle"
aria-hidden="true">
<div class="modal-dialog modal-dialog-centered col-12 col-md-8 modal-lg" role="document">
<div class="modal-content">
<div class="col-12 px-0">
<div id="itemImage{{item.pk}}Carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
{% for image in item.itemimage_set.all %}
<li data-target="#itemImage{{item.pk}}Carousel" data-slide-to="{{forloop.counter0}}"
{% if forloop.first %} class="active" {% endif %}></li>
{% endfor %}
</ol>
<div class="carousel-inner shadow-lg rounded-sm">
{% for image in item.itemimage_set.all %}
<div class="carousel-item {% if forloop.first %} active {% endif %}">
<img src="{{image.image.url}}" class="d-block w-100" alt="...">
</div>
{% endfor %}
</div>
{% if item.itemimage_set.count > 1 %}
<a class="carousel-control-prev" href="#itemImage{{item.pk}}Carousel" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#itemImage{{item.pk}}Carousel" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
{% endif %}
</div>
</div>
</div>
</div>
</div>
Data structure:
class Item(models.Model):
name = ... etc.
class ItemImage(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
image = models.ImageField(upload_to='itemimages', null=True, blank=True)
As you can see, there are 5 forloop cycles in the template which leads to frequent queries from the database over the same set of data.
What I've tried:
I've tried to replace {% for image in item.itemimage_set.all %} with {% for image in item.load_related_itemimage %}, and in the models.py:
class Item(models.Model):
name = ...
def load_related_itemimage(self):
return self.itemimage_set.prefetch_related('image')
and this prompt error:
'image' does not resolve to an item that supports prefetching - this is an invalid parameter to prefetch_related().
I'm actually quite new to django and am not sure how to use select_related or prefetch_related but so far I've employed them and managed to reduce database query from 150 to 30+. And I think the frequency can be further reduced due to the silly cycles above as you can see.
forward the Debug Toolbar data for the page:
SELECT "appname_itemimage"."id",
"appname_itemimage"."item_id",
"appname_itemimage"."image"
FROM "appname_itemimage"
WHERE "appname_itemimage"."item_id" = '19'
5 similar queries. Duplicated 5 times.
5 similar queries. Duplicated 5 times. is bad right?
view.py
class ItemDetailView(DetailView):
'''display an individual item'''
model = Item
template_name = 'boutique/item.html'
Thanks for #Iain Shelvington's answer, his solution for the above code works like a charm, how about this:
I think they are related so I didn't separate this to raise another question -- what if the item itself is in a forloop? how to use prefetch_related in this situation? thanks!
{% for item in subcategory.item_set.all %}
<img src="{{ item.itemimage_set.first.image.url }}">
{% endfor %}
because I need to access item.itemimage_set when looping through subcateogry.item_set, and this is a much worse problem than before, because it raises 19 repetition in loading itemimage
This template is rendered by a ListView
class CategoryListView(ListView):
'''display a list of items'''
model = Category
# paginate_by = 1
template_name = 'boutique/show_category.html'
context_object_name = 'category_shown'
def get_queryset(self):
qs = super().get_queryset().get_categories_with_item()
self.gender = self.kwargs.get('gender') # reuse in context
gender = self.gender
request = self.request
# fetch filter-form data
self.category_selected = request.GET.get('category_selected')
self.brand_selected = request.GET.get('brand_selected')
self.min_price = request.GET.get('min_price')
self.max_price = request.GET.get('max_price')
if gender == 'women':
self.gender_number = 1
elif gender == 'men':
self.gender_number = 2
else:
raise Http404
get_category_selected = Category.objects.filter(
gender=self.gender_number, name__iexact=self.category_selected).first()
category_selected_pk = get_category_selected.pk if get_category_selected else None
get_subcategory_selected = SubCategory.objects.filter(
category__gender=self.gender_number, name__iexact=self.category_selected).first()
subcategory_selected_pk = get_subcategory_selected.pk if get_subcategory_selected else None
category_pk = category_selected_pk if category_selected_pk else self.kwargs.get(
'category_pk')
subcategory_pk = subcategory_selected_pk if subcategory_selected_pk else self.kwargs.get(
'subcategory_pk')
# print('\nself.kwargs:\n', gender, category_pk, subcategory_pk)
if gender and not category_pk and not subcategory_pk:
qs = qs.get_categories_by_gender(gender)
# print('\nCategoryLV_qs_gender= ', '\n', qs, '\n', gender, '\n')
return qs
elif gender and category_pk:
qs = qs.filter(pk=category_pk)
# print('\nCategoryLV_qs_category= ', '\n', qs, '\n')
return qs
elif gender and subcategory_pk:
qs = SubCategory.objects.annotate(Count('item')).exclude(
item__count=0).filter(pk=subcategory_pk)
self.context_object_name = 'subcategory_shown'
# print('\nCategoryLV_qs_sub_category= ', '\n', qs, '\n')
return qs
def get_validated_cats(self):
categories_validated = []
subcategories_validated = []
items_validated = []
brand_selected = self.brand_selected
min_price = self.min_price
if min_price == '' or min_price is None:
min_price = 0
max_price = self.max_price
if max_price == '' or max_price is None:
max_price = 999999
for item in Item.objects.select_related('category', 'subcategory', 'tag').filter(category__gender=self.gender_number):
if int(min_price) <= item.final_price < int(max_price):
if brand_selected is None or brand_selected == 'бренд' or item.brand.name == brand_selected:
items_validated.append(item)
if item.category not in categories_validated:
categories_validated.append(item.category)
if item.subcategory not in subcategories_validated:
subcategories_validated.append(item.subcategory)
return categories_validated, subcategories_validated, items_validated
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['brands'] = Brand.objects.all()
cat_valid, subcat_valid, items_valid = self.get_validated_cats()
context['filter_context'] = {
'gender': self.gender,
'gender_number': self.gender_number,
'category_selected': self.category_selected,
'brand_selected': self.brand_selected,
'min_price': self.min_price,
'max_price': self.max_price,
'categories_validated': cat_valid,
'subcategories_validated': subcat_valid,
'items_validated': items_valid,
}
# print(context)
return context
You should use prefetch_related to prefetch "itemimage_set" so that every time you access item.itemimage_set.all you get the cached result
item = get_object_or_404(Item.objects.prefetch_related('itemimage_set'), pk=pk)
For a DetailView
class ItemDetailView(DetailView):
model = Item
queryset = Item.objects.prefetch_related('itemimage_set')
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 %}