How to list latest posts in Django?

Question:

I’m working on my blog. I’m trying to list my latest posts in page list_posts.html.I tried but posts are not shown, I don’t know why. I don’t get any errors or anything, any idea why my posts aren’t listed?

This is models.py

from django.db import models
from django.utils import timezone
from ckeditor.fields import RichTextField
from stdimage import StdImageField

STATUS = (
    (0,"Publish"),
    (1,"Draft"),
)

class Category(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
    title = models.CharField(max_length=255, verbose_name="Title")

    class Meta:
        verbose_name = "Category"
        verbose_name_plural = "Categories"
        ordering = ['title']

    def __str__(self):
        return self.title

class Post(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="Created at")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="Updated at")
    is_published = models.BooleanField(default=False, verbose_name="Is published?")
    published_at = models.DateTimeField(null=True, blank=True, editable=False, verbose_name="Published at")
    title = models.CharField(max_length=200, verbose_name="Title")
    slug = models.SlugField(max_length=200, unique=True)
    author = models.ForeignKey('auth.User', verbose_name="Author", on_delete=models.CASCADE)
    category = models.ForeignKey(Category, verbose_name="Category", on_delete=models.CASCADE)
    body = RichTextField(blank=True, null=True)
    image = StdImageField(upload_to='featured_image/%Y/%m/%d/', variations={'standard':(1170,820),'banner':(1170,530),'thumbnail':(500,500)})
    status = models.IntegerField(choices=STATUS, default=0)

    class Meta:
        verbose_name = "Post"
        verbose_name_plural = "Posts"
        ordering = ['-created_at']

    def publish(self):
        self.is_published = True
        self.published_at = timezone.now()
        self.save()

    def __str__(self):
        return self.title

This is views.py

from django.shortcuts import render, get_object_or_404
from django.utils import timezone
from .models import Category, Post

def post_list(request):
    posts =  Post.objects.filter(published_at__lte=timezone.now()).order_by('published_at')
    latest_posts =  Post.objects.filter(published_at__lte=timezone.now()).order_by('published_at')[:5]

    context = {'posts': posts, 'latest_posts': latest_posts}
    return render(request, 'list_posts.html', context)

def post_detail(request, pk, post):
    latest_posts =  Post.objects.filter(published_at__lte=timezone.now()).order_by('published_at')[:5]
    post = get_object_or_404(Post, pk=pk)

    context = {'post': post, 'latest_posts': latest_posts}
    return render(request, 'post_detail.html', context)

This is list_posts.html

{% extends "base.html" %}
{% load static %} 
        {% block content %}
        <!-- Main Wrap Start -->
        <main class="position-relative">
            <div class="post-carausel-1-items mb-50">
                {% for post in latest_posts %}
                <div class="col">
                    <div class="slider-single bg-white p-10 border-radius-15">
                        <div class="img-hover-scale border-radius-10">
                            <span class="top-right-icon bg-dark"><i class="mdi mdi-flash-on"></i></span>
                            <a href="{{ post.get_absolute_url }}">
                                <img class="border-radius-10" src="{{ post.image.standard.url }}" alt="post-slider">
                            </a>
                        </div>
                        <h6 class="post-title pr-5 pl-5 mb-10 mt-15 text-limit-2-row">
                            <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
                        </h6>
                        <div class="entry-meta meta-1 font-x-small color-grey float-left text-uppercase pl-5 pb-15">
                            <span class="post-by">By <a href="#">{{ post.author }}</a></span>
                            <span class="post-on">{{ post.created_at}}</span>
                        </div>
                    </div>
                </div>
                {% endfor %}
            </div>
        </main>
        {% endblock content%}

Everything works except that posts aren’t listed. Why I don’t get listed posts?

Thanks in advance!

Asked By: Firefoxer

||

Answers:

The reason this doesn’t work is because the published_at is apparently NULL and is thus never filled in. With the .filter(published_at__lte=timezone.now()), it checks that the published_at is less than or equal to the current timestamp. If it is NULL, it thus is excluded. That means that you will either need to fill in the published_at some way, or filter (and order) with a different field, like created_at. You can thus work with:

from django.db.models.functions import Now
from django.shortcuts import get_object_or_404, render

from .models import Category, Post


def post_list(request):
    posts = Post.objects.filter(created_at__lte=Now()).order_by('-created_at')
    latest_posts = posts[:5]
    context = {'posts': posts, 'latest_posts': latest_posts}
    return render(request, 'list_posts.html', context)


def post_detail(request, pk, post):
    latest_posts = Post.objects.filter(created_at__lte=Now()).order_by(
        '-created_at'
    )[:5]
    post = get_object_or_404(Post, pk=pk)
    context = {'post': post, 'latest_posts': latest_posts}
    return render(request, 'post_detail.html', context)

Note: You can work with Now [Django-doc] to work with the database timestamp instead. This can be useful if you want to specify the queryset in a class-based view, since each time the queryset is evaluated, it will then take the (updated) timestamp.

Answered By: Willem Van Onsem
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.