Django - Post list not appearing - python

Django blog posts not appearing
I am new to Django and am trying to return a list of published blog posts.
The page is appearing and no errors are produced, however no posts are showing. I have checked in the admin page and all posts are published.
Model:
class BlogPost(models.Model):
title = models.CharField(max_length=200)
snippet = models.CharField(max_length=400, null=True)
Blog_pic = models.ImageField(upload_to='blog_pics',blank=True)
hero_pic = models.ImageField(upload_to='blog_pics',blank=True)
content = models.TextField()
blogcategory = models.CharField(max_length=200, default='uncategorised')
create_date = models.DateTimeField(default=timezone.now())
published_date = models.DateTimeField(blank=True, null=True)
#def publish(self):
# self.published_date = timezone.now()
# self.save()
def get_absolute_url(self):
return reverse("BlogPost_detail",kwargs={'pk':self.pk})
Views:
class BlogPostListView(ListView):
model = BlogPost
def get_queryset(self):
return BlogPost.objects.all().order_by('-published_date')
class BlogPostDetailView(DetailView):
model = BlogPost
Template:
{% for BlogPost in BlogPost_list %}
<div class="col-sm-6">
<a href="{% url 'BlogPost_detail' pk=BlogPost.pk %}">
<div class="card">
<img src="#">
<div class="">
<h4><span class="">{{ BlogPost.category }}</span></h4>
<p class="">{{ BlogPost.tile }}</p>
<p class="">{{ BlogPost.snippet }}</p>
<p style="">{{ BlogPost.published_date }</p>
<p style="">x min</p>
</div>
</div>
</a>
</div>
{% endfor %}

Related

How to hide a category without articles?

I have articles combined by categories. Here are data models:
class Category(models.Model):
name = models.CharField(max_length=200, verbose_name='Наименование')
slug = models.SlugField(max_length=250, verbose_name='URL')
created = models.DateTimeField(auto_now_add=True, verbose_name='Добавлено')
objects = models.Manager()
class Meta:
ordering = ('name',)
verbose_name = 'категорию'
verbose_name_plural = 'Категории'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('main:article_list_by_category', args=[self.slug])
class Article(models.Model):
STATUS_CHOICES = (
('draft', 'Черновик'),
('published', 'Опубликовано'),
)
TYPE_ARTICLE_CHOICES = (
('Руководство', 'Руководство'),
('Инструкция', 'Инструкция'),
)
title = models.CharField(max_length=250, verbose_name='Заголовок')
slug = models.SlugField(max_length=250, unique_for_date='publish', verbose_name='URL')
type_article = models.CharField(max_length=15, choices=TYPE_ARTICLE_CHOICES, default='Инструкция',
verbose_name='Тип статьи')
category = models.ForeignKey(Category,
related_name='article',
on_delete=models.CASCADE, verbose_name='Категория')
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts', verbose_name='Автор')
body = RichTextUploadingField(verbose_name='Статья')
publish = models.DateTimeField(default=timezone.now, verbose_name='Опубликовано')
created = models.DateTimeField(auto_now_add=True, verbose_name='Добавлено')
updated = models.DateTimeField(auto_now=True, verbose_name='Обновлено')
status = models.CharField(max_length=12, choices=STATUS_CHOICES, default='draft', verbose_name='Статус')
tags = TaggableManager()
private = models.BooleanField(default=False, verbose_name='Приватная статья')
objects = models.Manager()
published = PublishedManager()
class Meta:
ordering = ('-publish',)
verbose_name = 'статью'
verbose_name_plural = 'Статьи'
index_together = (('id', 'slug'),)
indexes = [GinIndex(fields=['title'])]
def __str__(self):
return self.title
Here is the output template:
<div class="container my-container-style">
<div class="row">
<div class="col-md-3">
<h4 class="mb-4 category">Категории</h4>
<div id="sidebar">
<ul>
<li {% if not category %} class="selected" {% endif %}>
Все
</li>
{% for c in categories %}
<li {% if category.slug == c.slug %} class="selected" {% endif %}>
{{ c.name }}
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="col-md-9">
{% if tag %}
<h2 class="tag_title">Статьи с тегами: "{{ tag.name }}"</h2>
{% endif %}
{% for articles in Article %}
<div class="article col-md-12">
<h2 class="article_title">{{ articles.title }}</h2>
<div class="article_info">
<span>Автор: {{ articles.author.first_name }} &#171{{ articles.author }}&#187 {{ articles.author.last_name }}</span>
<span>Обновлено: {{ articles.updated|date:'d-m-Y' }}</span>
<span>Тип статьи: {{ articles.type_article }}</span>
</div>
<div class="article_body">
<p>{{ articles.body|safe|truncatewords:30 }}</p>
</div>
<div class="read_more">
<p class="mb-4"><a class="btn btn-secondary button_read back" href="{{ articles.get_absolute_url }}" role="button">Читать далее »</a></p>
</div>
</div>
{% endfor %}
{% include "pagination.html" with page=Article %}
</div>
</div>
</div>
I've found similar question (Django how hide empty category) but I can't hide a category with my own filter. How to properly hide a category with zero articles in it?

Display the number of comments of each post related to the same post in django

Hello friends I am building a blog and I have encountered a problem. My problem is that when I want to display the number of comments for each post, on the main page of the blog number of comments displays all posts that have comments, but the number of comments for each post is the same. In the event that post 2 has 3 comments and the other has 1 comment.
You can see in this picture.
Image
This is Post model
class Post(models.Model):
STATUS_CHOICES = (
('draft', 'Draft'),
('published', 'Published'),
)
title = models.CharField(max_length=255, unique=True)
slug = models.SlugField(max_length=255, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
created_date = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
image = models.ImageField(null=True, blank=True, upload_to="images/")
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[self.created_date.year,
self.created_date.strftime('%m'),
self.created_date.strftime('%d'),
self.slug])
def active_comment(self):
return self.comments.filter(active=True)
This is Comment model
class Comment(models.Model):
post = models.ForeignKey(Post, related_name="comments", on_delete=models.CASCADE)
name = models.CharField(max_length=100)
email = models.EmailField()
comment = models.CharField(max_length=500)
active = models.BooleanField(default=False)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return "{} by {}".format(self.comment, self.name)
This is my views.py
def post_list(request):
posts = models.Post.objects.filter(status='published')
paginator = Paginator(posts, 4)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
comment_count = models.Comment.objects.filter(active=True).count()
context = {
'page_obj': page_obj,
'comment_count': comment_count,
}
# print(posts)
return render(request, "post_list.html", context=context)
And this too post_list.html
<article class="col-12 col-md-6 tm-post">
<hr class="tm-hr-primary">
<a href="{{ post.get_absolute_url }}"
class="effect-lily tm-post-link tm-pt-60">
<div class="tm-post-link-inner">
<img src="/{{ post.image }}/" alt="Image" class="img-fluid">
</div>
<h2 class="tm-pt-30 tm-color-primary tm-post-title">{{ post.title }}</h2>
</a>
<p class="tm-pt-30">
{{ post.body|slice:254 }}
</p>
<div class="d-flex justify-content-between tm-pt-45">
<span class="tm-color-primary">Travel . Events</span>
<span class="tm-color-primary">{{ post.created_date.year }}/{{ post.created_date.month }}/{{ post.created_date.day }}</span>
</div>
<hr>
<div class="d-flex justify-content-between">
<span>
{% for comment in post.active_comment|slice:"1" %}
{{ comment_count }}<span> Comment</span>
{% endfor %}
</span>
<span>{{ post.author|capfirst }}</span>
</div>
</article>
please guide me.
You can .annotate(…) [Django-doc] with:
from django.db.models import Count, Q
# …
posts = Post.objects.annotate(number_of_comments=Count('comment', filter=Q(comment__active=True)))
The Post objects that arise from this QuerySet will have an extra attribute .number_of_comments.
based on #willem post you need to edit your template accordingly too:
posts = Post.objects.annotate(number_of_comments=Count('comment', filter=Q(comment_set__active=True)))
and in the template
<div class="d-flex justify-content-between">
<span>{{post.number_of_comments}}</span>
<span>{{ post.author|capfirst }}</span>
</div>
You specified the related_name to be “comments” inside the comment model.
That is where the Fielderror is coming from
Change the “comment_set” inside the query to “comments” and let’s see

ValueError at /category/economy/: Field 'id' expected a number but got 'economy'

I try to add new path and this happen "Field 'id' expected a number but got 'economy'."
in traceback the highlighted line is in the views.py file which i mentioned below.
category_posts = Post.objects.filter(category=cats)
I am sharing my files plz help me to get rid of the issue.
urls.py
urlpatterns = [
path('',views.allpost,name="allpost"),
path('search', views.search, name="search"),
path('contact/', views.contact, name="contact"),
path('success/', views.successView, name="success"),
path('category/<str:cats>/', views.CategoryView, name ="category"),
path('<int:blog_id>/',views.detail,name="detail"),
] + static(settings.MEDIA_URL,document_root = settings.MEDIA_ROOT)
here i used str:cats, yet it shows "Field 'id' expected a number but got 'economy'."
views.py
def CategoryView(request, cats): # here cats is same which mentioned in dynamic url.
category_posts = Post.objects.filter(category=cats)
return render(request, 'categories.html', {'cats':cats.title(), 'category_posts':category_posts})
"category_posts = Post.objects.filter(category=cats)" this line of code shows in traceback
models.py
from django.db import models
class Category(models.Model):
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
title = models.CharField(max_length=255, verbose_name="Title")
parent = models.ForeignKey('self', related_name='children', on_delete=models.CASCADE, blank=
True, null=True)
class Meta:
verbose_name = "Category"
verbose_name_plural = "Categories"
ordering = ['title']
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=100)
public_date = models.DateField(null=True)
public_time = models.TimeField(null=True,default="")
category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name="Category", null=True)
image = models.ImageField(upload_to='images/',null=True, blank=True)
body = models.TextField()
class Meta:
verbose_name = "Post"
verbose_name_plural = "Posts"
ordering = ['public_date']
def summary(self):
return self.body[:100]
def pub_date(self):
return self.public_date.strftime('%b %e,%y')
# to give layout for time and date
def __str__(self):
return self.title
categories.html
{% extends 'base.html' %}
{%block content%}
<h1> Category: {{ cats }} </h1>
{% for post in category_posts %}
<div class="container mt-3">
<div class="row mb-2">
<div class="col-md-6">
<div class="card flex-md-row mb-4 box-shadow h-md-250">
<div class="card-body d-flex flex-column align-items-start">
<strong class="d-inline-block mb-2 text-primary">{{ post.category }}</strong>
<h3 class="mb-0">
<a class="text-dark" href="{% url 'detail' post.id %}">{{post.title}}</a>
</h3>
<div class="mb-1 text-muted">{{ post.public_date }}</div>
<p class="card-text mb-auto">{{ post.summary }}</p>
Continue reading
</div>
<img class="card-img-right flex-auto d-none d-md-block" data-src="holder.js/200x250?theme=thumb" alt="Thumbnail [200x250]" style="width: 200px; height: 250px;" src="data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%22200%22%20height%3D%22250%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20200%20250%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%3Cstyle%20type%3D%22text%2Fcss%22%3E%23holder_182c981dfc3%20text%20%7B%20fill%3A%23eceeef%3Bfont-weight%3Abold%3Bfont-family%3AArial%2C%20Helvetica%2C%20Open%20Sans%2C%20sans-serif%2C%20monospace%3Bfont-size%3A13pt%20%7D%20%3C%2Fstyle%3E%3C%2Fdefs%3E%3Cg%20id%3D%22holder_182c981dfc3%22%3E%3Crect%20width%3D%22200%22%20height%3D%22250%22%20fill%3D%22%2355595c%22%3E%3C%2Frect%3E%3Cg%3E%3Ctext%20x%3D%2256.20000076293945%22%20y%3D%22131%22%3EThumbnail%3C%2Ftext%3E%3C%2Fg%3E%3C%2Fg%3E%3C%2Fsvg%3E" data-holder-rendered="true">
</div>
</div>
</div>
</div>
{% endfor %}
{% else %}
<h2>Sorry this page does not exist....</h2>
{% endif %}
{%endblock%}
I am confused it demands. can someone help me to solve it plz.
Its because you are querying it wrong:
So instaed of doing this:
# views.py
def CategoryView(request, cats): # here cats is same which mentioned in dynamic url.
category_posts = Post.objects.filter(category=cats)
return render(request, 'categories.html', {'cats':cats.title(), 'category_posts':category_posts})
Try something with this query. I'm supposing you want to query all the posts of a specific category that will be coming from your URL.
from django.shortcuts import get_object_or_404
def CategoryView(request, cats):
# method 1
category_posts = Post.objects.filter(category__title=cats)
# method 2
category = Category.objects.get(title=cats)
category_posts = category.Category.all() # here .Category is the related_name you used in your Post model
# method 3:
category = get_object_or_404(Category, title=cats) # will raise 404 if no category found with the given title
category_posts = category.Category.all()
return render(request, 'categories.html', {'cats':cats.title(), 'category_posts':category_posts})
PS: When you don't know what your ForeignKey related_name should be. Then go for the plural name of the model. Like in the current case:
# models.py
category = models.ForeignKey(Category, on_delete=models.CASCADE, verbose_name="posts", null=True)
This way we can query like this category_posts = category.posts.all()

django error : NoReverseMatch at /watchlist/ Reverse for 'viewList' with arguments '('',)'

I am working on my project and the main idea is to add some items to the watchlist or "bookmark" some items:
when I render the page to see the watchlist that I add them by clicking on the "Add to watchlist button " Django give me this error:
NoReverseMatch at /watchlist/
Reverse for 'viewList' with arguments '('',)' not found. 1 pattern(s) tried: ['Post/(?P[0-9]+)$']
my code:
Model.py file
class Post(models.Model):
#data fields
title = models.CharField(max_length=64)
textarea = models.TextField()
#bid
price = models.FloatField(default=0)
currentBid = models.FloatField(blank=True, null=True)
imageurl = models.CharField(max_length=255, null=True, blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, default="No Category Yet!", null=True, blank=True)
creator = models.ForeignKey(User, on_delete=models.PROTECT)
date = models.DateTimeField(auto_now_add=True)
# for activated the Category
activate = models.BooleanField(default=True)
buyer = models.ForeignKey(User, null=True, on_delete=models.CASCADE, related_name="auctions_Post_creator")
############################### this is the watchers
watchers = models.ManyToManyField(User, blank=True, related_name='favorite')
def __str__(self):
return f"{self.title} | {self.textarea} | {self.date.strftime('%B %d %Y')}"
urls.py
urlpatterns =[
# Watchlist
path('Post/<int:id>/watchlist_post/change/<str:reverse_method>',
views.watchlist_post, name='watchlist_post'),
path('watchlist/', views.watchlist_list, name='watchlist_list')
path('Post/<int:id>', views.viewList, name='viewList'),
]
views.py
#start watchlist
def viewList(request, id):
# check for the watchlist
listing = Post.objects.get(id=id)
if listing.watchers.filter(id=request.user.id).exists():
is_watched = True
else:
is_watched = False
context = {
'listing': listing,
'comment_form': CommentForm(),
'comments': listing.get_comments.all(),
'Bidform': BidForm(),
# IS_WATCHED method
'is_watched': is_watched
}
return render(request, 'auctions/item.html', context)
#login_required
def watchlist_post(requset, id, reverse_method):
listing = get_object_or_404(Post, id=id)
if listing.watchers.filter(id=requset.user.id).exists():
listing.watchers.remove(requset.user)
else:
listing.watchers.add(requset.user)
if reverse_method == "viewList":
return viewList(requset, id)
return HttpResponseRedirect(reverse(reverse_method))
#login_required
def watchlist_list(request):
user = requset.user
watchers_items = user.favorite.all()
context = {
'watchers_items': watchers_items
}
return render(requset, 'auctions/watchlist.html', context)
HTML FILE: (item.html) this file for showing the post for exapmple : (title/ description/ date etc..)
<!-- check to add to watchlist -->
<div class="col">
{% if is_watched %}
Remove To Watchlist
<!-- remove it -->
{% else %}
Add To Watchlist
{% endif %}
</div>
HTML FILE (layout.html) for adding a link to the navbar for the page
<li class="nav-item">
<a class="nav-link" href="{% url 'watchlist_list' %}">Watchlist</a>
</li>
HTML FILE(whitchlsit page)
{% for post in watchers_items %}
<div class="col-sm-4">
<div class="card my-2">
<img src="{{post.imageurl}}" class="img-fluid">
<div class="card-body">
<div class="text-center py-2">
<h5 class="card-title text-info">{{post.title}}</h5>
<p class="alert alert-info">{{post.textarea}}</p>
<ul class="list-group">
<li class="list-group-item list-group-item-info">category: {{post.category.name}}</li>
<li class="list-group-item list-group-item-info">Price: {{post.price}}$</li>
<li class="list-group-item list-group-item-info">Created by: {{post.creator}}</li>
</ul>
</div>
<!-- Buttons -->
<div class="row">
<div class="col">
View
</div>
</div>
</div>
<div class="card-footer">
<small class="text-muted">Created since:{{post.date}}</small>
</div>
</div>
{% endfor %}
The culprit of this problem is that you are calling "{% url 'viewList' listing.id %}" even though viewList does not exist in your urls.py.
So, you can create one like this:
path("some/path", views.some_func, name="viewList")
EDIT
As the error says, listing.id is empty ({% url 'viewList' listing.id %}). So, you might want to do post.id instead because you are looping with the name of post.

Filtering many-to-one in Django template

Let's say I have these models:
class Profile(models.Model):
headline = models.CharField(max_length=200)
class ProfilePhoto(models.Model):
photo = models.ImageField(upload_to='profiles/photos')
owner = models.ForeignKey(Profile, related_name='photos', on_delete=models.CASCADE)
type_choices = (
('PR', 'Primary'),
('AD', 'Additional'),
)
type = models.CharField(max_length=2, choices=type_choices, default='AD')
and the following view:
def profiles(request):
# Retrieve all active profiles
profiles = Profile.objects.filter(status='AC').order_by('-updated_at')#.filter(photos__)
context = {'profiles': profiles}
return render(request, 'profiles.html', context)
and this in my template file:
{% for profile in profiles %}
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-12">
<div class="panel panel-default">
<div class="panel-body">
<p>{{ profile.headline }}</p>
<img src="{{ MEDIA_URL }}profiles/thumbs/{{ profile.photos.first.photo }}">
</div>
</div>
</div>
{% endfor %}
Here I get one photo for each profile because of profile.photos.first.photo in the template but what I want instead is to select a single photo for each profile with the condition that it has a type of 'PR'. Any help would be appreciated.
You can use a model method. Something like this:
class Profile(models.Model):
headline = models.CharField(max_length=200)
#property
def primary_profile_photo(self):
primary_photo = self.photos.filter(type='PR').order_by('?').first()
return primary_photo.photo
That would get you a random (order_by='?') photo, with type PR, that you could then access as primary_profile_photo in the template.

Categories