Way to show latest 4 blog posts on my page - django

I want to be able to show the latest 4 blog posts only. I can't seem to get them to show. Any help would be greatly appreciated.
Here is my code:
Models.py
class BlogPost(models.Model):
blog_title = models.CharField(max_length=48)
blog_article = RichTextUploadingField(null=True, blank=True, default="ici")
blog_image = models.ImageField(null=True, blank=True, upload_to="images", default="default.png")
blog_date = models.DateField(auto_now_add=True)
blog_published = models.BooleanField(default=False)
blog_featured = models.BooleanField(default=False)
def __str__(self):
return self.blog_title
Views.py
def blogTest(request):
posts = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('blog_date')
context_blog = {'posts': posts}
return render(request, 'blogtest.html', context_blog)
def latestPosts(request):
latest = BlogPost.objects.filter(blog_date__lte=timezone.now()).reverse()[:3]
return render(request, 'blogtest.html', {'latest': latest})
Template
<div class="blog-post-container">
<div class="row">
<h1 id="lastest-blogs-title" style="text-align: center;">Latest Blogs</h1>
{% for latestpost in latest %} {% if latestpost.blog_published is True %}
<div class="col-md-4" id="bloggrid1">
<hr>
<div class="blog-post">
<div class="blog-content">
<img class="blog-img"src="{{latestpost.blog_image.url}}"alt="My image"/>
<h2 class="blog-title">{{latestpost.blog_title}}</h2>
<hr id="blog-hr" style="width: 90%" />
<article class="blog-article">
<p>{{latestpost.blog_article|truncatechars_html:265|safe}}</p>
</article>
Read More...
<p class="blog-date">Posted on: {{latestpost.blog_date}}</p>
</div>
</div>
</div>
{% endif %} {% empty %}
<h3>No Blog Uploads</h3>
{% endfor %}
</div>
</div>
</div>
I have followed many other tutorials but I can't seem to see what I'm doing wrong here.

Try this if you want to get last 4 added entries based on primary key...
latest = BlogPost.objects.order_by('-pk')[:4]
Try this if you want to get last 4 added entries based on your date field
latest = BlogPost.objects.order_by('-blog_date')[:4]
Your template code is good to load entries passed through context

You need to sort queryset but not filter the queryset with blog_date
qs = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('-blog_date')[:3]

Related

Count number of replies on a particular post in Django

I want to count number of replies on a particular post in Django
View.py
def forum(request):
profile = Profile.objects.all()
if request.method=="POST":
user = request.user
image = request.user.profile.image
content = request.POST.get('content','')
post = Post(user1=user, post_content=content, image=image)
post.save()
messages.success(request, f'Your Question has been posted successfully!!')
return redirect('/forum')
posts = Post.objects.filter().order_by('-timestamp')
return render(request, "forum.html", {'posts':posts})
Reply code
def discussion(request, myid):
post = Post.objects.filter(id=myid).first()
replies = Replie.objects.filter(post=post)
if request.method=="POST":
user = request.user
image = request.user.profile.image
desc = request.POST.get('desc','')
post_id =request.POST.get('post_id','')
reply = Replie(user = user, reply_content = desc, post=post, image=image)
reply.save()
messages.success(request, f'Your Reply has been posted successfully!!')
return redirect('/forum')
return render(request, "discussion.html", {'post':post, 'replies':replies})
model.py
class Post(models.Model):
user1 = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
post_id = models.AutoField
post_content = models.CharField(max_length=5000)
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
def __str__(self):
return f'{self.user1} Post'
class Replie(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
reply_id = models.AutoField
reply_content = models.CharField(max_length=5000)
post = models.ForeignKey(Post, on_delete=models.CASCADE, default='')
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
def __str__(self):
return f'{self.user1} Post'
My Forum.html code:
{% for post in posts %}
<div class="container-fluid mt-10">
<div class="row">
<div class="col-md-12">
<div class="card mb-4 forumcardcss">
<div class="card-header forumcardheader">
<div class="media flex-wrap w-100 align-items-center imgcss"> <img src="/media/{{post.image}}"
class="d-block ui-w-40 rounded-circle" alt="profileimage"style="width: 40px;height: 40px;"> <p class="ml-4 usernamecss"> {{post.user1}} </p>
<div class="media-body ml-3"> <button class="btn btn-light" style="color:blue; font-size: 13px;">Add or See reply </button>
</div>
<div class="text-muted small ml-3">
<div class="px-4 pt-3">Nmber of reply {{post.timestamp}} </div>
</div>
{% if user.is_superuser or user.is_staff %}
<button class="btn btn-danger btn-sm" onclick="window.mytest()">Delete Post</button>
<script type="text/javascript">window.mytest = function() { var isValid = confirm('If you click ok then its delete this post and related reply on it. Are you sure to delete?');if (!isValid) { event.preventDefault(); alert("It wont delete. Yay!");}}</script>
{% endif %}
</div>
</div>
<div class="card-body forumcardbody">
<p>{{post.post_content}}</p>
</div>
<div class="card-footer d-flex flex-wrap justify-content-between align-items-center px-0 pt-0 pb-3">
</div>
</div>
</div>
</div>
</div>
{% endfor %}
I want to do like this
where on the place of Number of reply, I want to display the number of replies of the particular post
Is there any way to find if Question(Post) has been answered(reply) on my post page(forum.py)
I want to do it like this If the Question has been answered then it should show "Answered" else "Not answered yet"
#Eega suggested the right answer just some changes in the code will help you
class Post(models.Model):
user1 = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
post_id = models.AutoField
post_content = models.CharField(max_length=5000)
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
#property
def count_replies(self):
return self.replie_set.count()
def __str__(self):
return f'{self.user1} Post'
post = Post.objects.filter(id=myid).first() to post = Post.objects.filter(id=myid).first().prefetch_related('replies_set') This will make your query optimized
Also accept #Eega answer only, I have just showed you the edited code
Now I am suggesting one good method here
Post.objects.get(id=myid).annotate(post_count=Count("replie"))
Simply use this in your views without changing #models.py and access it in your template as post.post_count in for loop.
To archive this you can use the related name of the Post model (have a look at the documentation). Django will create a field for every foreign key that allows you to access the related model. By default, this will be named replie_set on the Post model.
This field you can then use to get the number of replies to a post by calling the count() method of the replie_set queryset. I would also add a method to the Post model that does that for you as a convenience.
To bring this together, your Post model would look like this:
class Post(models.Model):
user1 = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
post_id = models.AutoField
post_content = models.CharField(max_length=5000)
timestamp= models.DateTimeField(default=now)
image = models.ImageField(upload_to="images",default="")
#property
def count_replies():
return self.replies_set.count()
def __str__(self):
return f'{self.user1} Post'
Assuming that your forum.html template iterates over the posts like that:
{% for post in posts %}
...
<p>Posts: {{ post.count_replies }}</p>
...
{% endfor %}
You get the number of replies by calling post.count_replies(). Of course, if you don't want to add a dedicated method to the model you can just use do post.replie_set.count() directly.
An alternative - and more efficient method - is to annotate your posts with the reply count as Abdul Aziz Barkat suggests. To do this you have to change your view like that:
from django.db.models import Count
def forum(request):
profile = Profile.objects.all()
if request.method=="POST":
user = request.user
image = request.user.profile.image
content = request.POST.get('content','')
post = Post(user1=user, post_content=content, image=image)
post.save()
messages.success(request, f'Your Question has been posted successfully!!')
return redirect('/forum')
posts = Post.objects.annotate(count_replies=Count("replie")).order_by('-timestamp')
return render(request, "forum.html", {'posts':posts})
I changed only the second to last line here:
posts = Post.objects.annotate(count_replies=Count("replie")).order_by('-timestamp')
This adds the aggregated count of replies to each post as count_replies.
Then this value is used in the forum.html template like that:
{% for post in posts %}
<div class="container-fluid mt-10">
<div class="row">
<div class="col-md-12">
<div class="card mb-4 forumcardcss">
<div class="card-header forumcardheader">
<div class="media flex-wrap w-100 align-items-center imgcss"> <img src="/media/{{post.image}}"
class="d-block ui-w-40 rounded-circle" alt="profileimage"style="width: 40px;height: 40px;"> <p class="ml-4 usernamecss"> {{post.user1}} </p>
<div class="media-body ml-3"> <button class="btn btn-light" style="color:blue; font-size: 13px;">Add or See reply </button>
</div>
<div class="text-muted small ml-3">
<div class="px-4 pt-3">Number of replies {{ post.count_replies }} </div>
</div>
{% if user.is_superuser or user.is_staff %}
<button class="btn btn-danger btn-sm" onclick="window.mytest()">Delete Post</button>
<script type="text/javascript">window.mytest = function() { var isValid = confirm('If you click ok then its delete this post and related reply on it. Are you sure to delete?');if (!isValid) { event.preventDefault(); alert("It wont delete. Yay!");}}</script>
{% endif %}
</div>
</div>
<div class="card-body forumcardbody">
<p>{{post.post_content}}</p>
</div>
<div class="card-footer d-flex flex-wrap justify-content-between align-items-center px-0 pt-0 pb-3">
</div>
</div>
</div>
</div>
</div>
{% endfor %}
So, only a single line changed here either:
<div class="px-4 pt-3">Number of replies {{ post.count_replies }} </div>

Django Display count of database entries related via foreign key

I have two models, ProjectNotes and ProjectNoteComments. ProjectNoteComments are related to ProjectNotes via a foreign key. I want to display the number of comments each note has on a listview. I am just learning Django and so far I have not been able to figure out how to retrieve and display the comment count.
My view:
(I do import count)
class ProjectNotesList(ListView):
model = ProjectNotes
template_name = 'company_accounts/project_notes.html'
comments = ProjectNotes.comments
def related_project(self, **kwargs):
project = get_object_or_404(Project, id=self.kwargs.get('pk'))
notes = ProjectNotes.objects.all
return notes
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super().get_context_data(**kwargs)
context['project'] = get_object_or_404(Project, id=self.kwargs.get('pk'))
return context
commentscount = ProjectNotes.objects.annotate(num_comments=Count('comments'))
My template:
{% extends 'base.html' %}
{% block content %}
<div class="section-container container">
<h1>Notes for {{ project }}</h1>
{% if project.notes.all %}
{% for note in project.notes.all %}
<div class ="projectnotes-entry">
<div class="col-sm-8">
<div class="row-sm-6">
<div class="card mb-2">
<div class="card-body">
<div class="card-title">{{ note.title }}</div>
<div class="card-text">{{ note.body | safe | truncatewords:"20"|linebreaks }}
read more</div>
</div>
</div>
</div>
</div>
</div>
<h2>comments count</h2>
{{ commentscount }}
{% endfor %}
{% else %}
<p>No notes have been have been added yet.</p>
{% endif %}
</div>
{% endblock content %}
The models:
class ProjectNotes(models.Model):
title = models.CharField(max_length=200)
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
project = models.ForeignKey(Project, default=0, blank=True, on_delete=models.CASCADE, related_name='notes')
def __str__(self):
return self.title
class ProjectNoteComments(models.Model):
body = tinymce_models.HTMLField()
date = models.DateField(auto_now_add=True)
projectnote = models.ForeignKey(ProjectNotes, default=0, blank=True, on_delete=models.CASCADE, related_name='comments')
Short version:
{{ note.comments.all.count }} # possibly works also without 'all' but can't check right now
I've just answered similar problem with simple explanation of relationships.
https://stackoverflow.com/a/70955851/12775662
Read official docs, it's really rewarding. https://docs.djangoproject.com/en/4.0/topics/db/models/#relationships

How to list my categories and forums related to it? Django

Model
class Category(models.Model):
class Meta():
verbose_name_plural = "Categories"
cat_name = models.CharField(max_length=50)
description = models.TextField()
def get_forums(self):
get_forum = Forum.objects.filter(category=self)
return get_forum
def __str__(self):
return f"{self.cat_name}"
class Forum(models.Model):
class Meta():
verbose_name_plural = "Forums"
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="forums")
parent = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
forum_name = models.CharField(max_length=50)
description = models.TextField()
def __str__(self):
return f"{self.forum_name}"
Views
class Home(ListView):
model = Category
template_name = 'forums/index.html'
context_object_name = 'category'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['cat'] = Category.objects.all()
return context
HTML
{% block content %}
{% for cat in category %}
<div class="row">
<div class="bg-success rounded-top border border-dark" style="width:100%; padding-left:8px;">
{{cat.cat_name}}
</div>
</div>
<div class="row">
<div class="bg-secondary border border-dark" style="width:100%; padding-left:16px;">
Forums_Go_Here
</div>
</div>
{% endfor %}
{% endblock content %}
I am trying to get a homepage where I would be able to list my categories and show the forums in those categories.
The template I have is running a for loop which is looping through all Categories.
In the shell i am able to get the forums with the: Category.objects.get(pk=2).get_forums() command. But this limits it to one category.
You can use related name for that, no need to use additional method:
{% block content %}
{% for cat in category %}
<div class="row">
<div class="bg-success rounded-top border border-dark" style="width:100%; padding-left:8px;">
{{cat.cat_name}}
</div>
</div>
{% for forum in cat.forums.all %}
<div class="row">
<div class="bg-secondary border border-dark" style="width:100%; padding-left:16px;">
{{forum.forum_name}}
</div>
</div>
{% endfor%}
{% endfor %}
{% endblock content %}
Also you have a mistake there:
context['category'] = Category.objects.all()
If you want to access it as category in template put it there with that key, not cat.

Pass multiple objects to templates with render

I'm beginner on Django.
I have a project with the following models:
My Articles models:
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=160)
content = models.TextField()
image = models.ImageField(upload_to=upload_location)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
categorie = models.CharField(max_length=200)
categorie = models.ForeignKey('categorie.Categorie')
publier = models.BooleanField()
My Portfolio categories models which is linked with my Article Model:
class Categorieport(models.Model):
title = models.CharField(max_length=200)
article = models.OneToOneField('posts.Post')
And finally, my portfolio models with all the photos:
class Portfolio(models.Model):
title = models.CharField(max_length=200)
image = models.ImageField(upload_to=upload_location)
timestamp = models.DateTimeField(auto_now=False, auto_now_add=True)
updated = models.DateTimeField(auto_now=True, auto_now_add=False)
categorieportfolio = models.ForeignKey('Categorieport')
In one view and one template, i'd like to display information concerning the article and the portfolio related to the article.
I wrote the following view:
def portfolio(request, article=None):
portfolio = get_object_or_404(Categorieport, article=article)
image_portfolio = portfolio.portfolio_set.all()
return render(request, 'portfolio1.html', {'portfolio': portfolio, 'image_portfolio': image_portfolio})
And the following templates:
<div class="titre-display">
<h2>{{ portfolio.article.timestamp|date:"d E Y" }} / {{ portfolio.article.categorie}} </h2>
<h1>{{ portfolio.article.title}}</h1>
</div>
<div class="content-display">
<div class="content-display-main">
<div class="content-display-main-portfolio">
<div class="image-portfolio">
<a class="example-image-link" href="{{ image_portfolio.image.url }}" data-lightbox="example-set" data-title="{{image_portfolio.title}}">
</a>
I can access to information from my article but i can't access information from my portfolio. I tried it with the shell, and it works. I can't figure out why it doesn't work in my view and template.
Do you have any idea?
Thank you in advance
Singertwist
Your image_portfolio is a querySet, that's means is some kind of list, you have to use a loop to access the items and them access the properties:
<div class="content-display">
<div class="content-display-main">
<div class="content-display-main-portfolio">
<div class="image-portfolio">
{% for item_img in image_portfolio %}
<a class="example-image-link" href="{{ item_img.image.url }}" data-lightbox="example-set" data-title="{{item_img.title}}"></a>
{% endfor %}
Try this:
# views.py
def portfolio(request, article=None):
# first get the Post instance with slug = article (I'm assuming article passed as url argument, is a slug)
post = get_object_or_404(Post, slug=article)
# get the Categoriepost object based on a specifi article
categorie_port = get_object_or_404(Categorieport, article=post)
# image_portfolio is a QuerySet (that is a list of Portfolio objects)
image_portfolio = categorie_port.portfolio_set.all()
return render(request, 'portfolio1.html', {'portfolio': categorie_port, 'image_portfolio': image_portfolio})
Leave your HTML as is.
Hi thank you all for your answer.
So, I used a for loop for solving my case as mentioned previously.
Below, my code:
<div class="titre-display">
<h2>{{ portfolio.article.timestamp|date:"d E Y" }} / {{ portfolio.article.categorie}} </h2>
<h1>{{ portfolio.article.title}}</h1>
</div>
<div class="content-display">
<div class="content-display-main">
<div class="content-display-main-portfolio">
{% for photo in image_portfolio %}
<div class="image-portfolio">
<a class="example-image-link" href="{{ photo.image.url }}" data-lightbox="example-set" data-title="{{photo.title}}">
{% thumbnail photo.image "300x300" crop="center" as im %}
<img class="example-image" src="{{ im.url }}" alt=""/>
{% endthumbnail %}
</a>
<p>{{photo.title}}</p>
</div>
{% empty %}
<p>Aucun portfolio.</p>
{% endfor %}
</div>
</div>
And my views:
def portfolio(request, slug=None, article=None):
slug = get_object_or_404(Post, slug=slug)
portfolio = get_object_or_404(Categorieport, article=article)
image_portfolio = portfolio.portfolio_set.all()
return render(request, 'portfolio.html', {'portfolio': portfolio, 'image_portfolio': image_portfolio})
Thanks again for your help
Singertwist

Retrieve info from many-to-many relationship in django temaplate

I am creating a blog and have a many-to-many relationship between the posts and categories.
class Category(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField()
def __str__(self):
return self.title
class Post(models.Model):
title = models.CharField(max_length=255)
subtitle = models.CharField(max_length=255,null=True,blank=True)
published_date = models.DateTimeField(auto_now_add=True)
draft = models.BooleanField(default=True)
body = RichTextField(config_name='blog')
slug = models.SlugField()
categories = models.ManyToManyField(Category)
featured = models.BooleanField(default=False)
I am trying to retrieve the the list of categories associated to an individual post within the template so I can display those category titles at the bottom of the post.
Here is the template code which displays the posts properly but not the categories.
{% for post in blog_posts %}
<div class="post">
<div class="date">
{{post.published_date|date:"M"}}
<span class="day">{{post.published_date|date:"d"}}</span>
<span>{{post.published_date|date:"Y"}}</span>
</div>
<div class="entry">
<div class="page-header">
<h2 class="post-title">{{post.title}}</h2>
</div>
<blockquote>
<p><strong>{{post.subtitle}}</strong></p>
</blockquote>
<p>{{post.body|safe}}</p>
<div class="well well-small">
<i class="icon-th-list "></i> Categories:LIST CATEGORIES HERE
</div>
</div> <!--entry div-->
</div><!--post div-->
{% endfor %}
Does anyone have thoughts on how I could retrieve the categories for a specific post? I greatly appreciate the time and expertise.
You can access the categories with this
{% for category in post.categories.all %}
{{ category.title }}
{% endfor %}
I also recommend adding .prefetch_related('categories') to the queryset in your view to reduce the number of sql queries.