I am currently working on a django blog and I've coded a search bar where you type something and, if there's any post that contains what you've typed in the title, it should appear all the posts. This part is perfectly well-written. However, there's an error with the pagination. As you'll see in the views.py. The maximum num of posts per page is 3. However, you can see there's four. However, the paginator detects there should be another page for the fourth posts. Here's an image that shows that.
Here's the views.py:
class ElementSearchView(View):
elements_list = Element.objects.all()
def get(self, request, *args, **kwargs):
paginator = Paginator(self.elements_list, 3)
page_request_var = 'page'
page = request.GET.get(page_request_var)
try:
paginated_queryset = paginator.page(page)
except PageNotAnInteger:
paginated_queryset = paginator.page(1)
except EmptyPage:
paginated_queryset = paginator.page(paginator.num_pages)
queryset = Element.objects.all()
query = request.GET.get('q')
if query:
queryset = queryset.filter(
Q(title__icontains=query)
).distinct()
context = {
'query': queryset,
'queryset': paginated_queryset,
'page_request_var': page_request_var,
}
return render(request, 'periodic/search_results_table.html', context)
And here's the html template: The pagination is at the end of the template.
{% load static %}
<html>
{% include 'periodic/head_search.html' %}
<body>
{% include 'periodic/header.html' %}
<br>
<br>
<div class="container">
<div class="row">
<!-- Latest Posts -->
<main class="posts-listing col-lg-8">
<div class="container">
<div class="row">
<!-- post -->
{% for element in query %}
<div class="post col-xl-6 wrap-login100">
<div class="post-thumbnail"><img src="{{ element.thumbnail.url }}" alt="..." class="img-fluid"></div>
<div class="post-details">
<a href="{{ element.get_absolute_url }}">
<h3 class="h4">{{ element.title }}</h3></a>
</div>
</div>
{% endfor %}
</div>
<!-- Pagination -->
<nav aria-label="Page navigation example">
<ul class="pagination pagination-template d-flex justify-content-center">
{% if queryset.has_previous %}
<li class="page-item"> <i class="fa fa-angle-left"></i></li>
{% endif %}
<li class="page-item">{{ queryset.number }}</li>
{% if queryset.has_next %}
<li class="page-item"> <i class="fa fa-angle-right"></i></li>
{% endif %}
</ul>
</nav>
{% if is_paginated %}
<nav aria-label="Page navigation example">
<ul class="pagination pagination-template d-flex justify-content-center">
{% if page_obj.has_previous %}
<li class="page-item"> <i class="fa fa-angle-left"></i></li>
{% endif %}
<li class="page-item">{{ page_obj.number }}</li>
{% if page_obj.has_next %}
<li class="page-item"> <i class="fa fa-angle-right"></i></li>
{% endif %}
</ul>
</nav>
{% endif %}
</div>
</main>
</body>
{% include 'periodic/scripts_search.html' %}
</html>
As the user #ikilnac mentioned,
you are looping over the original queryset and not the paged one in your template
That simply means that in your loop, you do this
{% for element in query %}
<div class="post col-xl-6 wrap-login100">
<div class="post-thumbnail"><img src="{{ element.thumbnail.url }}" alt="..." class="img-fluid"></div>
<div class="post-details">
<a href="{{ element.get_absolute_url }}">
<h3 class="h4">{{ element.title }}</h3></a>
</div>
</div>
{% endfor %}
And then after that, you are using the tag in the form of {% if queryset.has_previous %} with the original queryset rather than the paged one in the template (the query).
There's a good example of it here - Paginate with Django
Related
I am currently facing this problem with Django ListView. Basically, I need to filter some questions per topic and I would like to paginate the results.
My code is working perfectly about the queryset part (the results are showed correctly) but I am facing a problem with pagination.
Let's say I have so far 8 items in my query, if I choose to paginate_by = 10, it shows me just one page. If, otherwise, I choose to paginate by, let's say, 3, it shows me 3 pages to choose in the template (which is correct) but it shows me ALL the results of the query in my page.
I post some code to be more clear
models.py:
class Tag(models.Model):
name = models.CharField(max_length=300, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def clean(self):
self.name = self.name.capitalize()
def __str__(self):
return self.name
class Question(models.Model):
post_owner = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=5000, default='')
body = tinymce_models.HTMLField()
tags = models.ManyToManyField(
Tag, related_name='tags')
viewers = models.ManyToManyField(
User, related_name='viewed_posts', blank=True)
views.py:
class TagQuestionsListView(ListView):
template_name = 'main/tag_questions.html'
paginate_by = 20
def get_queryset(self, **kwargs):
tag = Tag.objects.get(name=self.kwargs['name'])
questions = Question.objects.filter(tags=tag)
return questions
def get_contextdata(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tag'] = Tag.objects.get(name=self.kwargs['name'])
context['questions'] = Question.objects.filter(
tags=context['tag'], is_deleted=False)
return context
template:
{% extends 'base.html' %}
{% load humanize %}
{% block title %}Domande su {{tag.name}}{% endblock title %}
{% block content %}
<style>
.text {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2; /* number of lines to show */
line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>
<div class="card">
<div class="mt-3">
<h3 class="ms-2" style="display: inline;">Ultime {{ questions.count }} Domande</h3>
{% if request.user.is_authenticated %}
Fai una domanda
{% else %}
Fai una domanda
{% endif %}
</div>
<h5 class="ms-2">{{ total_questions.count }} domande totali </h5>
<hr>
{% for question in questions %}
<div class="row">
<div class="col-2 ms-2">
<p>{{ question.count_all_the_votes }} Voti</p>
<p>{{ question.count_answers }} Risposte</p>
<p>{{ question.calculate_viewers }} Visualizzazioni</p>
</div>
<div class="col-9">
<h5>{{question.title}}</h5>
<div class="text">
{{ question.body|striptags }}
</div>
{% for tag in question.tags.all %}
<a class="btn btn-sm btn-outline-primary m-1" href="{% url 'main:tag_questions' name=tag.name %}">{{tag.name}}</a>
{% endfor %}
<div class="float-end">
<a style="display: inline;" href="">{{question.post_owner}}</a>
{% if question.is_edited == False %}
<span style="display:inline;">creata {{question.created_at | naturaltime}}</span>
{% else %}
<span style="display:inline;"> modificata {{question.edited_time | naturaltime}} da <a style="display: inline;" href="">{{question.edited_by.username}}</a></span>
{% endif %}
</div>
</div>
</div>
<hr>
{% endfor %}
</div>
<div class="row mt-3">
<div class="col-lg-12">
<div class="card">
<div class="card-body">
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if page_obj.has_previous %}
<li class="page-item"><a class="page-link" href="{% url 'main:tag_questions' name=tag.name %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.previous_page_number }}">Precedente</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">Precedente</a></li>
{% endif %}
{% for i in paginator.page_range %}
<li class="page-item {% if page_obj.number == i%} active {% endif %} %} "><a class="page-link" href="?filter={{ filter }}&orderby={{ orderby }}&page={{ i }}">{{i}}</a></li>
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item"><a class="page-link" href="{% url 'main:tag_questions' name=tag.name %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.next_page_number }}">Prossima</a></li>
{% else %}
<li class="page-item disabled"><a class="page-link" href="#">Prossima</a></li>
{% endif %}
</ul>
</nav>
</div>
</div>
</div>
{% endblock content %}
With this I want my comment converter to answer.
You have to use page_obj instead questions in your template.
<--! ⬇️⬇️⬇️ -->
{% for question in page_obj %}
<div class="row">
<div class="col-2 ms-2">
<p>{{ question.count_all_the_votes }} Voti</p>
<p>{{ question.count_answers }} Risposte</p>
<p>{{ question.calculate_viewers }} Visualizzazioni</p>
</div>
<div class="col-9">
<h5>{{question.title}}</h5>
<div class="text">
{{ question.body|striptags }}
</div>
{% for tag in question.tags.all %}
<a class="btn btn-sm btn-outline-primary m-1" href="{% url 'main:tag_questions' name=tag.name %}">{{tag.name}}</a>
{% endfor %}
<div class="float-end">
<a style="display: inline;" href="">{{question.post_owner}}</a>
{% if question.is_edited == False %}
<span style="display:inline;">creata {{question.created_at | naturaltime}}</span>
{% else %}
<span style="display:inline;"> modificata {{question.edited_time | naturaltime}} da <a style="display: inline;" href="">{{question.edited_by.username}}</a></span>
{% endif %}
</div>
</div>
</div>
<hr>
{% endfor %}
So, if you define attribute paginate_by , than ListView(django docs) adds a paginator and page_obj to the context. To allow the users to navigate between pages, add links to the next and previous page, in your template.
I have an URL field in Django to which I am adding the URL of a photo, how can I render this image to the frontend of my website.
models.py file code for reference
class Place(models.Model):
place_photo = models.ImageField(upload_to='photos/%Y/%m/%d/')
place_photo_1 = models.ImageField(upload_to='photos/%Y/%m/%d/')
place_photo_2 = models.ImageField(upload_to='photos/%Y/%m/%d/')
place_photo_3 = models.ImageField(upload_to='photos/%Y/%m/%d/')
place_photo_4 = models.ImageField(upload_to='photos/%Y/%m/%d/')
field_name = models.URLField(max_length=500,default='add photo url')
def __str__(self):
return self.place_title
This is my template.html code
<div class="placebox-overlap-wrapper">
<div class="overlap-box">
<div class="overlap-btns-area">
<div class="car-magnify-gallery">
<a href="{{place.place_photo.url}}" class="overlap-btn">
<i class="fa fa-expand"></i>
<img class="hidden" src="{{place.place_photo.url}}">
</a>
{% if place.place_photo_1 %}
<a href="{{place.place_photo_1.url}}" class="hidden"
data-sub-html="<h4>{{place.place_title}}</h4><p>{{place.story1}}</p>">
<img class="hidden" src="{{place.place_photo_1.url}}">
</a>
{% endif %}
{% if place.place_photo_2 %}
<a href="{{place.place_photo_2.url}}" class="hidden"
data-sub-html="<h4>{{place.place_title}}</h4><p>{{place.story2}}</p>">
<img class="hidden" src="{{place.place_photo_2.url}}">
</a>
{% endif %}
{% if place.place_photo_3 %}
<a href="{{place.place_photo_3.url}}" class="hidden"
data-sub-html="<h4>{{place.place_title}}</h4><p>{{place.story3}}</p>">
<img class="hidden" src="{{place.place_photo_3.url}}">
</a>
{% endif %}
{% if place.place_photo_4 %}
<a href="{{place.place_photo_4.url}}" class="hidden"
data-sub-html="<h4>{{place.place_title}}</h4><p>{{place.story4}}</p>">
<img class="hidden" src="{{place.place_photo_4.url}}">
</a>
{% endif %}
{% if place.place_photo_5 %}
<a href="{{place.place_photo_5.url}}" class="hidden"
data-sub-html="<h4>{{place.place_title}}</h4><p>{{place.story5}}</p>">
<img class="hidden" src="{{place.place_photo_5.url}}">
</a>
{% endif %}
{% if place.field_name %}
<a href="{{place.field_name}}" class="hidden"
data-sub-html="<h4>{{place.place_title}}</h4><p>{{place.story5}}</p>">
<img class="hidden" src="{{place.field_name}}">
</a>
{% endif %}
</div>
</div>
</div>
</div>
This is my: Admin file reference
Showing 5 images to the frontend: frontend part of the website
Problem part : Not showing URL part image
This is my view.py
def place(request):
places = Place.objects.order_by('-added_date')
paginator = Paginator(places,9)
page = request.GET.get('page')
paged_places = paginator.get_page(page)
country_search = Place.objects.values_list('country',flat=True).distinct()
location_search = Place.objects.values_list('location',flat=True).distinct()
architecture_search = Place.objects.values_list('architecture',flat=True).distinct()
data = {
'places': paged_places,
'country_search':country_search,
'location_search': location_search,
'architecture_search': architecture_search,
}
return render(request,'place/place.html',data)
I am new to Django, so if I am doing any mistake then please help me out. It would be really appreciable
I'm currently working on an e-commerce site and I'm trying to create a product list page that spans into another page after 4 items have been displayed. rendering the page doesn't produce any error but all items in the database are displayed on the same page and remains the same even after switching to another page.
Here's my views.py:
from django.shortcuts import render, get_object_or_404
from .models import Category, Item
from django.core.paginator import Paginator
def item_list(request, category_slug=None):
category = None
categories = Category.objects.all()
items = Item.objects.filter(available=True)
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
items = items.filter(category=category)
paginator = Paginator(items, 4)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request,
'item/list.html',
{'category': category,
'categories': categories,
'page_obj': page_obj,
'items': items})
my urls.py file:
from django.urls import path
from . import views
app_name = 'shop'
urlpatterns = [
path('', views.item_list, name='item_list'),
path('<slug:category_slug>/', views.item_list, name='item_list'),
path('<int:id>/<slug:slug>/', views.item_detail, name='item_detail'),
]
pagination snippet from the template
<nav class="d-flex justify-content-center wow fadeIn">
<ul class="pagination pg-blue">
<!--Arrow left-->
{% if page_obj.has_previous %}
Previous
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
Next
{% endif %}
</ul>
</nav>
and the logic that displays the products
<div class="row wow fadeIn">
<!--Grid column-->
{% for item in items %}
<div class="col-lg-3 col-md-6 mb-4">
<!--Card-->
<div class="card" style="width: 16rem; height: 25rem">
<!--Card image-->
<div class="view overlay">
<a href="{{ item.get_absolute_url }}">
{% if item.tags and item.label %}
<div class="imgHolder">
<img src="{{ item.image.url }}" class="img-fluid">
<span class="badge badge-pill {{ item.get_label_display }}-color">{{ item.tags }}</span>
</div>
{% else %}
<img src="{{ item.image.url }}" class="img-fluid">
{% endif %}
</a>
<a href="{{ item.get_absolute_url }}">
<div class="mask rgba-white-slight"></div>
</a>
</div>
<!--Card image-->
<!--Card content-->
<div class="card-body text-center" style="height: 9rem;">
<!--Category & Title-->
<a href="{{ item.category.get_absolute_url }}" class="grey-text">
<h5>{{ item.category.name|truncatechars:20 }}</h5>
</a>
<h5>
<strong style="color:red">
{{ item.name }}
</strong>
</h5>
<h6 class="font-weight-bold">
{% if item.discount_price %}
<strong><del>${{ item.price}}</del></strong>
<strong>${{ item.discount_price }}</strong>
{% else %}
<strong>${{ item.price }}</strong>
{% endif %}
</h6>
</div>
<!--Card content-->
</div>
<!--Card-->
</div>
{% endfor %}
</div>
I'd really like to know what I'm doing wrong and I'm also open to alternative means of solving the same problem. Thanks
You are using all the queryset that you are passing to the paginator. You must iterate over the page_obj.object_list.
page_obj = paginator.get_page(page_number)
page_obj_items = page_obj.object_list
you need to loop throw {% for item in page_obj %}
I'm learning programming and following a tutorial using django 3, the same I'm using.
The text and images are not displaying on the frontend on one particular html file.
1.-In settings.py I have this:
MEDIA_ROOT= os.path.join(BASE_DIR,"media")
MEDIA_URL= "/media/"
2.-In models.py:
class Property(models.Model):
title = models.CharField(max_length=200)
main_photo = models.ImageField(upload_to='photos/%Y/%m/%d/')
3.-In admin.py:
from django.contrib import admin
from .models import Property
class PropertyAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'is_published')
list_display_links = ('id', 'title')
search_fields = ('title', 'town')
list_editable = ('is_published',)
list_per_page = 30
admin.site.register(Property, PropertyAdmin)
Then I migrated to the DB, I created a properties.html and the loop {{ property.main_photo.url }} or {{ property.title }} is working and getting images and texts on this properties file:
{% extends 'base.html' %}
{% load humanize %}
{% block content %}
<section id="showcase-inner" class="py-5 text-white">
<div class="container">
<div class="row text-center">
<div class="col-md-12">
<h1 class="display-4">Browse Our Properties</h1>
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Sunt, pariatur!</p>
</div>
</div>
</div>
</section>
<!-- Listings -->
<section id="listings" class="py-4">
<div class="container">
<div class="row">
{% if properties %}
{% for property in properties %}
<div class="col-md-6 col-lg-4 mb-4">
<div class="card listing-preview">
<img class="card-img-top" src="{{ property.main_photo.url }}" alt="">
<div class="card-img-overlay">
<h2>
<span class="badge badge-secondary text-white">From {{ property.price_per_week | intcomma }}€ per week</span>
</h2>
</div>
<div class="card-body">
<div class="listing-heading text-center">
<h4 class="text-primary">{{ property.title }}</h4>
<p>
<i class="fas fa-map-marker text-secondary"></i> {{ property.town }}</p>
</div>
<hr>
<div class="row py-2 text-secondary">
<div class="col-6">
<i class="fas fa-check"></i> {{ property.swimming_pool }}</div>
<div class="col-6">
<i class="fas fa-wifi"></i> {{ property.free_wifi }}</div>
</div>
<div class="row py-2 text-secondary">
<div class="col-6">
<i class="fas fa-bed"></i> Bedrooms: {{ property.bedrooms }}</div>
<div class="col-6">
<i class="fas fa-bath"></i> Bathrooms: {{ property.bathrooms }}</div>
</div>
More Info
</div>
</div>
</div>
{% endfor %}
{% else %}
<div class="col-md-12">
<p>No Properties available</p>
</div>
{% endif %}
</div>
<div class="row">
<div class="col-md-12">
{% if properties.has_other_pages %}
<ul class="pagination">
{% if properties.has_previous %}
<li class="page-item">
<a href="?page={{properties.previous_page_number}}" class="page-link">«
</a>
</li>
{% else %}
<li class="page-item-disabled">
<a class="page-link">«</a>
</li>
{% endif %}
{% for i in properties.paginator.page_range %}
{% if properties.number == i %}
<li class="page-item active">
<a class="page-link">{{i}}</a>
</li>
{% else %}
<li class="page-item">
{{i}}
</li>
{% endif %}
{% endfor %}
</ul>
{% endif %}
</div>
</div>
</div>
</section>
{% endblock %}
The next step is to create a property.html file and also use loop, but everything that uses the loop doble curly braces are not displaying:
{% extends 'base.html' %}
{% load humanize %}
{% block content %}
<section id="showcase-inner" class="py-5 text-white">
<div class="container">
<div class="row text-center">
<div class="col-md-12">
<h1 class="display-4">{{ property.title }}</h1>
<p class="lead">
<i class="fas fa-map-marker"></i> {{ property.town }}</p>
</div>
</div>
</div>
</section>
{% endblock %}
I checked multiple times and my code is exactly like on the tutorial but my frontend is not displaying.
Views.py:
from django.shortcuts import get_object_or_404, render
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from .models import Property
def index(request):
properties = Property.objects.get_queryset().order_by('id').filter(is_published=True)
paginator = Paginator(properties, 30)
page = request.GET.get('page')
paged_properties = paginator.get_page(page)
context = {
'properties': paged_properties
}
return render(request, 'properties/properties.html', context)
def property(request, property_id):
property = get_object_or_404(Property, pk=property_id)
context = {
'property': property
}
return render(request, 'properties/property.html')
def search(request):
return render(request, 'properties/search.html')
You are not passing the context to properties/property.html inside def property(..., ...)
Change:
return render(request, 'properties/property.html')
To:
return render(request, 'properties/property.html', context)
I am trying to use a pagination to paginate one of my pages. I have tried a few different methods I have found online but for some reason, when I use paginate_by = 3, it doesn't actually paginate anything, yet still shows the html for the pagination at the bottom of the page.
View:
class SearchListView(ListView):
model = Post
template_name = "public/search.html"
paginate_by = 3
HTML:
{% extends 'public/base.html' %}
{% load staticfiles %}
{% block head %}
<link rel="stylesheet" type="text/css" href="{% static "public/css/search.css" %}" />
{% endblock %}
{% block content%}
<div class="search container-fluid">
<img src="/media/about-us.jpg" alt="">
<div class="search-title">
<h1 class="title">Search</h1>
</div>
<div class="search-main mb-5">
<form method='GET' action=''>
<input type="text" name='q' class="homebanner-search" placeholder="Enter your keywords" value='{{ request.get.q }}'>
</form>
</div>
</div>
<div class="container mt-5 mb-5">
<div class="detail-container">
{% for post in queryset %}
<a href="{% url 'post-detail' post.slug %}">
<div class="post-main">
<div class="post-image">
<img src="{{ post.image.url }}" class="card-img-top" alt="#">
<p class="post-category">{{ post.category }}</p>
</div>
<div class="post-body">
<div class="post-title">
<p class="post-title-p">Day in the life of {{ post.title }}</p>
</div>
<div class="post-text">
<p class="post-author-text text-muted">{{ post.sub_description|truncatewords:22 }}</p>
</div>
<div class="post-button">
<p>READ MORE ></p>
</div>
</div>
</div>
</a>
{% endfor %}
</div>
<div id="page_navigation" >
{% if is_paginated %}
<ul class="pagination">
{% if page_obj.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
</div>
</div>
{% endblock %}
So on the page, 3 items should be showing, and pagination should take me to the the next set of 3. The html is showing, and when I click the links it is taking me 2 page 2. The problem is the fact that 6 items are showing, and not 3, and when I go to page 2, there are the same 6 items there.
Unfortunately I couldn't reproduce your error exactly, but what did happen is that my objects wouldn't render when looping through queryset. So what I would recommend is try to loop through object_list instead:
{% for post in object_list %}
{{ post.name }}
{% endfor %}
Another thing you can do is add a context_object_name argument to your view:
class SearchListView(ListView):
model = Post
template_name = "public/search.html"
paginate_by = 3
context_object_name = 'posts'
and then loop through that:
{% for post in posts %}
{{ post.name }}
{% endfor %}
Also, I can't visualise what the search form is doing on this page since the ListView's model (Post) is the queryset, not whatever is searched for? So perhaps the link href is causing some trouble. Maybe try something like this instead:
<li>«</li>
Again, I could not reproduce the exact problem you are having, which is a shame because I feel like I have had the same issue before, so these are just suggestions pieced together from pagination that works for me and the code you posted. Hope it points you in the right direction.