I am new to Django and I just picked up a book "Django 2 by example". I followed all the code in the tutorial bu something broke the pagination along the line and I just can't figure what it is. I get an output of "Page of ." instead of "Page 1 of 1. at the base of my blog. Find some of my code below:. P.S: Kindly ignore the indentation in the code. Thank you.
Views.py
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.views.generic import ListView
from django.core.mail import send_mail
from django.db.models import Count
from taggit.models import Tag
from .models import Post, Comment
from .forms import EmailPostForm, CommentForm
def post_list(request, tag_slug=None):
object_list = Post.published.all()
tag = None`
if tag_slug:
tag = get_object_or_404(Tag, slug=tag_slug)
object_list = object_list.filter(tags__in=[tag])
paginator = Paginator(object_list, 3) # 3 posts in each page
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer deliver the first page
posts = paginator.page(1)
except EmptyPage:
# If page is out of range deliver last page of results
posts = paginator.page(paginator.num_pages)
return render(request,
'blog/post/list.html',
{'page': page,
'posts': posts,
'tag' : tag})
list.html
{% extends "blog/base.html" %}
{% block title %}My Blog{% endblock %}
{% block content %}
<h1>My Blog</h1>
{% if tag %}
<h2>Posts tagged with "{{ tag.name }}"</h2>
{% endif %}
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="tags">
Tags:
{% for tag in post.tags.all %}
<a href="{% url "blog:post_list_by_tag" tag.slug %}">
{{ tag.name }}
</a>
{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% include "pagination.html" with page=page_obj %}
{% endblock %}
Pagination.html (template)
<div class="pagination">
<span class="step-links">
{% if page.has_previous %}
Previous
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages}}.
</span>
{% if page.has_next %}
Next
{% endif %}
</span>
</div>
Related
Based on this tutorial https://www.youtube.com/watch?v=An4hW4TjKhE&ab_channel=AbhishekVerma
I'm trying to add the ability to add comments under posts, add a comment in the admin panel, everything is ok, but the site does not display anything under the post
here is models.py
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
class Post(models.Model):
published = None
title = models.CharField(max_length=200)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
header_image = models.ImageField(blank=True, null=True, upload_to="images/", default='fox.jpeg')
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='post_post')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_user')
content = models.TextField(max_length=160)
timestamp = models.DateTimeField(auto_now_add=True)
def __str__(self):
return '{}-{}'.format(self.post.title, str(self.user.username))
views.py
from django.http import HttpResponseRedirect
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Post, Comment
from django import forms
from .forms import *
class BlogListView(ListView):
model = Post
template_name = 'home.html'
context_object_name = 'posts'
paginate_by = 2
queryset = Post.objects.all()
class BlogDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class BlogCreateView(CreateView):
model = Post
template_name = 'post_new.html'
fields = ['title', 'author', 'body', 'header_image']
class BlogUpdateView(UpdateView):
model = Post
template_name = 'post_edit.html'
fields = ['title', 'body', 'header_image']
class BlogDeleteView(DeleteView):
model = Post
template_name = 'post_delete.html'
success_url = reverse_lazy('home')
#property
def image_url(self):
"""
Return self.photo.url if self.photo is not None,
'url' exist and has a value, else, return None.
"""
if self.image:
return getattr(self.photo, 'url', None)
return None
def post_detail(request, id, slug):
post = get_object_or_404(Post, id=id, slug=slug)
comments = Comment.objects.filter(post=post).order_by('-id')
is_liked = False
if post.likes.filter(id=request.user.id).exists():
is_liked = True
if request.method == 'POST':
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
content = request.POST.get('content')
comment = Comment.objects.create(post=post, user=request.user, content=content)
comment.save()
return HttpResponseRedirect(post.get_absolute_url())
else:
comment_form = CommentForm()
context = {
'post': post,
'is_liked': is_liked,
'total_likes': post.total_likes(),
'comments': comments,
'comment_form': comment_form,
}
return render(request, 'myblog/post_detail.html', context) #his "blog" = my "myblog"
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('content',)
post_detail.html
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
<p>+ Edit Blog Post</p>
<p>+ Delete Blog Post</p>
<img src="{{ post.header_image.url|default_if_none:'fox.jpeg' }}">
{{ post.body|urlize }}
{% for comm in post.commentpost_set.all%}
{{ comm.user }} <br>
{{ comm.text }} <br><br>
{% endfor %}
{% endblock content %}
<br><br>
<hr>
<form method="post">
{% csrf_token %}
{{ comment_form.as_p }}
{% if request.user.is_authenticated %}
<input type="submit" value="Submit" class="btn btn-outline-success">
{% else %}
<input type="submit" value="Submit" class="btn btn-outline-success" disabled>
{% endif %}
</form>
<div class="main-comment-section">
{{ comments.count }} Comment{{ comments|pluralize }}
{% for comment in comments %}
<blockquote class="blockquote">
<p class="mb-0">{{ comment.content }}</p>
<footer class="blockquote-footer">by <cite title="Source Title">{{ comment.user|capfirst }}</cite></footer>
</blockquote>
{% endfor %}
</div>
myblog/urls.py
from django.urls import path
from .views import (
BlogListView,
BlogDetailView,
BlogCreateView,
BlogUpdateView,
BlogDeleteView,
)
urlpatterns = [
path('post/new/', BlogCreateView.as_view(), name='post_new'),
path('post/<int:pk>/', BlogDetailView.as_view(), name='post_detail'),
path('post/<int:pk>/edit/',BlogUpdateView.as_view(), name='post_edit'),
path('post/<int:pk>/delete/',BlogDeleteView.as_view(), name='post_delete'),
path('', BlogListView.as_view(), name='home'),
]
base.html
{% load static %}
<html>
<head>
<title>Django blog</title>
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:400"
rel="stylesheet">
<link href="{% static 'css/base.css' %}" rel="stylesheet">
</head>
<body>
<div>
<header>
<div class="nav-left">
<h1>Django blog</h1>
<h2>Admin</h2>
</div>
<div class="nav-right">
+ New Blog Post
</div>
</header>
{% if user.is_authenticated %}
<p>Hi {{ user.username }}!</p>
{% else %}
<p>You are not logged in.</p>
Log In<br>
<p>Sign up</p>
{% endif %}
{% block content %}
{% endblock content %}
</div>
</body>
</html>
<ul class="pagination">
{% if page_obj.has_previous %}
{% if page_obj.number|add:'-3' > 1 %}
<li class="pagination__item">
1
</li>
{% endif %}
{% if page_obj.number|add:'-3' >= 3 %}
<li class="pagination__item pagination__item--dots">
<a href="?{{ genre }}{{ year }}page={{ page_obj.previous_page_number|add:'-3' }}">
<span class="pagination__link">• • •</span>
</a>
</li>
{% endif %}
{% endif %}
{% if paginator.page_range|length > 1 %}
{% for i in paginator.page_range %}
{% if page_obj.number == i %}
<li class="pagination__item active">
<a class="pagination__link" href="#">{{ i }}</a>
</li>
{% elif i > page_obj.number|add:'-4' and i < page_obj.number|add:'4' %}
<li class="pagination__item">
<a class="pagination__link" href="?{{ genre }}{{ year }}page={{ i }}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% endif %}
{% if page_obj.has_next %}
{% if page_obj.number|add:'4' < page_obj.paginator.num_pages %}
<li class="pagination__item pagination__item--dots">
<a href="?{{ genre }}{{ year }}page={{ page_obj.next_page_number|add:'3' }}">
<span class="pagination__link">• • •</span>
</a>
</li>
{% endif %}
{% if page_obj.number|add:'3' < page_obj.paginator.num_pages %}
<li class="pagination__item">
<a class="pagination__link" href="?{{ genre }}{{ year }}page={{ page_obj.paginator.num_pages }}">
{{ page_obj.paginator.num_pages }}
</a>
</li>
{% endif %}
{% endif %}
</ul>
Thanks for any help
Your post_detail.html extends base.html, hence any content you wish to render must be inside some block and this block also must be present in the parent template (base.html here). You currently have some content outside any block and hence they aren't rendered. Put the HTML inside the block and it will show up:
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
<p>+ Edit Blog Post</p>
<p>+ Delete Blog Post</p>
<img src="{{ post.header_image.url|default_if_none:'fox.jpeg' }}">
{{ post.body|urlize }}
{% for comm in post.commentpost_set.all%}
{{ comm.user }} <br>
{{ comm.text }} <br><br>
{% endfor %}
<!-- put them inside the block -->
<br><br>
<hr>
<form method="post">
{% csrf_token %}
{{ comment_form.as_p }}
{% if request.user.is_authenticated %}
<input type="submit" value="Submit" class="btn btn-outline-success">
{% else %}
<input type="submit" value="Submit" class="btn btn-outline-success" disabled>
{% endif %}
</form>
<div class="main-comment-section">
{{ comments.count }} Comment{{ comments|pluralize }}
{% for comment in comments %}
<blockquote class="blockquote">
<p class="mb-0">{{ comment.content }}</p>
<footer class="blockquote-footer">by <cite title="Source Title">{{ comment.user|capfirst }}</cite></footer>
</blockquote>
{% endfor %}
</div>
{% endblock content %}
I am following a specific guide and basically hit a roadblock I cannot debug.
I implemented Paginator into my blog site and was hoping to show the current page / end of page.
But for some reason the page values are blank.
What would you think is the reason behind this issue? Do you think that this has something to do with my VS compiler not importing paginator properly?
list HTML
pagination block code
<div class="pagination">
<span class="step-links">
{% if page.has_previous %}
Previous
{% endif %}
<span class="current">
Page {{ page.number }} of {{ page.paginator.num_pages }}.
</span>
{% if page.has_next %}
Next
{% endif %}
</span>
</div>
views.py
from django.shortcuts import render, get_object_or_404
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from .models import Post
# Create your views here.
def post_list(request):
object_list = Post.published.all()
paginator = Paginator(object_list, 3) # 3 posts in each page
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer deliver the first page
posts = paginator.page(1)
except EmptyPage:
# If page is out of range deliver last page of results
posts = paginator.page(paginator.num_pages)
return render(request,
'blog/post/list.html',
{'page': page,
'posts': posts})
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)
return render(request,
'blog/post/detail.html',
{'post': post})
List HTML Code
{% extends "blog/base.html" %}
{% block title %} My Blog {% endblock %}
{% block content %}
<h1>My Blog</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% include "pagination.html" with page=post %}
{% endblock %}
Github Link
Try using page=posts rather than page=post.
{% include "pagination.html" with page=posts %}
I have a page blog.html, and pagination sequence loads just fine, but I query the paginator to show one element on a page to test if pagination works. I have 4 items in the DB, the pagination reads 4 elements, but shows all elements on all pages.
views.py
def blog(request):
blog_cat = Blog_Categorie.objects.all()
all_blog = Blog.objects.all()
page = request.GET.get('page')
paginator = Paginator(all_blog, 1)
try:
blog = paginator.page(page)
except PageNotAnInteger:
blog = paginator.page(1)
except EmptyPage:
blog = paginator.page(paginator.num_pages)
return render_to_response('blog.html',
'blog':all_blog,'blog_cat':blog_cat,'blog_p':blog})
blog.html
<div class="col-lg-12 col-md-12 text-center">
{% if blog_p.has_other_pages %}
<ul class="pagination">
{% if blog_p.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in blog_p.paginator.page_range %}
{% if blog_p.number == i %}
<li class="active"><span>{{ i }}</span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if blog_p.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
{% endif %}
</div>
Seems you are iterating over blog_p.paginator.page_range. Do iterate over blog_p.
For doc
I have implemented infinite scroll for my data objects using jQuery and Waypoints. Works fine but I want to make it more convenient.
First of all I`m looking for a way to preserve position after page reload.
Also would be nice to add fixed pagination bar with a possibility to dislay your curent page dynamically while scrolling. I have add one, but how to dynamically display your position. Implies, I have 20 objects per page, when scrolling down for 20 next it should automatically switch current page for second one on pagination bar. And vice versa for scrolling up.
Another question is when choosing exact page at my current pagination menu it opens separate page with link 'http://127.0.0.1:8000/?page=2' for example, and displays objects only from 41th to 60th. I need it to open exact page but with possibility to scroll up and down for previous and next pages. Which way it`s possible to do this?
Here is my code below.
models.py
from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
class Bancnote(models.Model):
type = models.CharField(max_length=11)
par = models.PositiveIntegerField()
year_from = models.PositiveIntegerField()
year_to = models.PositiveIntegerField()
size = models.CharField(max_length=7)
sign = models.CharField(max_length=20)
desc = models.TextField(max_length=200)
image = models.ImageField(upload_to='bons_images')
def __str__(self):
return str(self.par) + ' ' + self.type + ' ' + str(self.year_from) + '-' + str(self.year_to)
views.py
from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage
from django.shortcuts import render, render_to_response
from django.template import RequestContext
from django.views import generic
from catalogue.models import Bancnote
def index(request):
bons_list = Bancnote.objects.all().order_by('par')
page = request.GET.get('page', 1)
paginator = Paginator(bons_list, 20)
try:
bons = paginator.page(page)
except PageNotAnInteger:
bons = paginator.page(1)
except EmptyPage:
bons = paginator.page(paginator.num_pages)
return render(request, 'catalogue/index.html', {'bons': bons})
def image(request):
bons = Bancnote()
variables = RequestContext(request, {
'bons': bons
})
return render_to_response('catalogue/bon_detail.html', variables)
urls.py
from django.conf.urls import url
from django.views.generic import DetailView
from catalogue import views
from catalogue.models import Bancnote
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^(?P<pk>\d+)$', DetailView.as_view(model=Bancnote, template_name='catalogue/bon_detail.html'))
]
index.html
{% extends 'catalogue/base.html' %}
{% block title %}Catalogue{% endblock %}
{% include 'catalogue/includes/header.html'%}
{% block content %}
{% if bons %}
<div class="container-fluid infinite-container">
<div class="row infinite-item">
{% for bon in bons %}
{% if forloop.counter0|divisibleby:"4" %}
</div>
<div class="row infinite-item">
{% endif %}
<div class="col-sm-3 col-lg-3">
<div style="display: block; text-align: center; margin: 0 auto">
<a href="{{ bon.id }}">
<img src="{{ bon.image.url }}" style="width: 50%; height: 50%"/>
<h5>{{ bon.par }} {{ bon.type }} {{ bon.year_from}}-{{ bon.year_to }}</h5>
</a>
</div>
</div>
{% endfor %}
</div>
</div>
{% if bons.has_next %}
<a class="infinite-more-link" href="?page={{ bons.next_page_number }}">More</a>
{% endif %}
<div class="loading" style="display: none;">
Loading...
</div>
{% if bons.has_other_pages %}
<div style="position:fixed; left: 50%; top: 93%;">
<ul class="pagination" id="pag">
{% if bons.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in bons.paginator.page_range %}
{% if bons.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if bons.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
{% endif %}
</ul>
</div>
{% endif %}
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0],
onBeforePageLoad: function () {
$('.loading').show();
},
onAfterPageLoad: function ($items) {
$('.loading').hide();
}
});
</script>
{% endif %}
{% endblock %}
{% include 'catalogue/includes/footer.html' %}
What I have now
Choosing exact page at pagination menu opens separate page
I have a lots of apps, but I want to generate all app's data on my homepage. Here's my apps:blog,members
I want to show blogs and my members on my homepage
I know that if I want to generate one app's data,I can do this:
blog/urls.py:
urlpatterns = [
url(r'^$', ListView.as_view(
queryset=Post.objects.all().order_by("-date")[:10],
template_name='blog1.html')),
and in blog1.html:
{% extends "index.html" %}
{% block blog %}
{% for post in blog_post %}
<div id="blog-wrapper" class="bgrid-third s-bgrid-half mob-bgrid-whole group">
<article class="bgrid">
<h5>{{ post.date }} </h5>
<h3><div class = "entry-title">{{ post.title }}</div></h3>
<p>{{ post.user }}</p>
<p><div class = "post_body">{{ post.body|safe|linebreaks }}</div></p>
</article>
</div>
{% endfor %}
{% endblock %}
{% block member %}
Here when I go to the url,I can see all blogs I write,but now I want to see blogs and members(another app) on one page, so how can I do this?
I would suggest you to use ListView's get_context_data method.
Create view in your project's views.py:
from django.views.generic import ListView
# Import your models here.
class HomepageView(ListView):
model = Post
ordering = '-date'
template_name = 'blog1.html'
context_object_name = 'posts'
def get_context_data(self, **kwargs):
context = super(HomepageView, self).get_context_data(**kwargs)
context['members'] = Member.objects.all()
return context
def get_queryset(self):
return super(HomepageView, self).get_queryset()[:10]
Then, change urls.py:
from django.conf.urls import url
# Import ``HomepageView`` here.
urlpatterns = [
url(r'^$', HomepageView.as_view(), name='homepage'),
# Other patterns here.
]
Now you can access posts using posts variable and members using members variable.
from .models import Post
from member.models import UserProfile
def get_data():
return {
"post": Post.objects.all().order_by("-date")[:10],
"user": UserProfile.objects.all()[:10]
}
then in my blog1.html:
{% extends "index.html" %}
{% block blog %}
{% for post in object_list.post %}
<div id="blog-wrapper" class="bgrid-third s-bgrid-half mob-bgrid-whole group">
<article class="bgrid">
<h5>{{ post.date }} </h5>
<h3><div class = "entry-title">{{ post.title }}</div></h3>
<p>{{ post.user }}</p>
<p><div class = "post_body">{{ post.body|safe|linebreaks }}</div></p>
</article>
</div>
{% endfor %}
{% endblock %}
{% block member %}
{% for post in object_list.user %}
<div class="bgrid member">
<div class="member-header">
<div class="member-pic">
<img src="{{ post.portrait }}" alt=""/>
</div>
<div class="member-name">
<h3>{{ post.user }}</h3>
<span>Creative Director</span>
</div>
</div>
<p>{{ post.intro }}</p>
<ul class="member-social">
<li><i class="fa fa-google-plus"></i></li>
<li><i class="fa fa-github"></i></li>
</ul>
</div> <!-- /member -->
{% endfor %}
{% endblock %}