I'm a newbie in Python and I need some help with my code. Not even sure if my title makes sense.
Basically I have my blog and I'm trying to add a sidebar with popular posts. I have created a PostStatistics class to collect the number of visits in each post which can be seen from Django admin.
The PostStatistics class has a ForeignKey to the Post class.
OK, so my problem is in the PostDetail view. I have a QuerySet there called Popular where I retrieve the 5 most popular posts in the last 7 days. There I retrieve the Post_id and Post__Title. I also need to retrieve the Post SLUG but I have no idea how I can do that.
The slug would be used in the following bit of code:
<a href="{% url 'post_detail' pop_article.post_slug %}">{{ pop_article.post__title }}</a>
The following is what in my models:
class Post(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='blog_posts')
updated_on = models.DateTimeField(auto_now=True)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
status = models.IntegerField(choices=STATUS, default=0)
views = models.PositiveIntegerField(default=0, editable=False)
class Meta:
ordering = ['-created_on']
db_table = "post"
def __str__(self):
return self.title
def get_absolute_url(self):
from django.urls import reverse
return reverse("post_detail", kwargs={"slug": str(self.slug)})
class PostStatistic(models.Model): class Meta: db_table = "PostStatistic"
post = models.ForeignKey(Post, on_delete=models.CASCADE)
date = models.DateField('Date', default=timezone.now)
views = models.IntegerField('Views', default=0)
def __str__(self):
return self.post.title
The following is what is in my views:
def PostDetail(request, slug):
template_name = 'post_detail.html'
post = get_object_or_404(Post, slug=slug)
comments = post.comments.filter(active=True)
new_comment = None
context = {}
obj, created = PostStatistic.objects.get_or_create(
defaults={
"post": post,
"date": timezone.now()
},
# At the same time define a fence or statistics object creation
# by two fields: date and a foreign key to the article
date=timezone.now(), post=post
)
obj.views += 1
obj.save(update_fields=['views'])
# Now pick up the list of the last 5 most popular articles of the week
popular = PostStatistic.objects.filter(
# filter records in the last 7 days
date__range=[timezone.now() - timezone.timedelta(7), timezone.now()]
).values(
'post_id', 'post__title'
).annotate(
views=Sum('views')
).order_by(
# sort the records Descending
'-views')[:5] # Take 5 last records
# Comment posted
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Create Comment object but don't save to database yet
new_comment = comment_form.save(commit=False)
# Assign the current post to the comment
new_comment.post = post
# Save the comment to the database
new_comment.save()
else:
comment_form = CommentForm()
return render(request, template_name, {'post': post,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form,
'popular_list': popular
},)
The following is in my HTML:
<div class="card-body">
{% if popular_list %}
<p class="card-text">
{% for pop_article in popular_list %}
<a href="{% url 'post_detail' pop_article.post_slug %}">{{ pop_article.post__title }}</a>
<br>
{% endfor %}
</p>
{% endif %}
</div>
Thanks in advance!
you need to add post__slug
in values
of this query in view function like this
popular = PostStatistic.objects.filter(
# filter records in the last 7 days
date__range=[timezone.now() - timezone.timedelta(7), timezone.now()]
).values(
'post_id','post__slug' ,'post__title'
).annotate(
views=Sum('views')
).order_by(
# sort the records Descending
'-views')[:5]
then you will be able to do like this in the template
<a href="{% url 'post_detail' pop_article.post__slug %}">{{ pop_article.post__title }}</a>