The Home Page displays all published Blog Posts in a professional Bootstrap card layout.
Only posts marked as IsPublished=True should be visible on the website.
from django.shortcuts import render
from .models import Post
def home(request):
posts = Post.objects.filter(
IsPublished=True
).order_by('-PublishDate')
return render(
request,
'home.html',
{
'posts': posts
}
)
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
]
We will display all published Blog Posts using a responsive Bootstrap Card layout.
Each card displays the Featured Image, Category, Title, Summary, Publish Date and a Read More button.
{% extends 'base.html' %}
{% block content %}
<div class="container mt-5">
<div class="text-center mb-5">
<h1>Django Blog Portal</h1>
<p class="text-muted">
Learn • Explore • Build with Django
</p>
</div>
<div class="row">
{% for post in posts %}
<div class="col-md-4 mb-4">
<div class="card h-100 shadow-sm">
<img src="{{ post.Image.url }}"
class="card-img-top"
alt="{{ post.Title }}">
<div class="card-body">
<span class="badge bg-primary">
{{ post.Category }}
</span>
<h5 class="card-title mt-3">
{{ post.Title }}
</h5>
<p class="card-text">
{{ post.Summary }}
</p>
</div>
<div class="card-footer bg-white border-0">
<small class="text-muted">
{{ post.PublishDate }}
</small>
<a href="#"
class="btn btn-primary btn-sm float-end">
Read More
</a>
</div>
</div>
</div>
{% empty %}
<div class="col-12">
<div class="alert alert-warning">
No Blog Posts Available.
</div>
</div>
{% endfor %}
</div>
</div>
{% endblock %}
| Tag | Purpose |
|---|---|
| {% for %} | Loops through all Blog Posts. |
| {{ post.Image.url }} | Displays the uploaded Featured Image. |
| {{ post.Category }} | Displays the Category Name. |
| {% empty %} | Displays a message when no Blog Posts are available. |
When a user clicks the Read More button, the complete Blog Article should be displayed.
We will use the Slug field to create SEO-friendly URLs.
from django.urls import path
from . import views
urlpatterns = [
path('', views.home, name='home'),
path(
'post/<slug:slug>/',
views.blogDetails,
name='blogdetails'
),
]
from django.shortcuts import (
render,
get_object_or_404
)
from .models import Post
def blogDetails(request, slug):
post = get_object_or_404(
Post,
Slug=slug,
IsPublished=True
)
return render(
request,
'blogdetails.html',
{
'post': post
}
)
<a href="{% url 'blogdetails' post.Slug %}"
class="btn btn-primary btn-sm float-end">
Read More
</a>
Instead of opening a Blog using an Id such as /post/1, Django generates a readable URL like /post/learning-django-orm/. This is easier to understand and is better for SEO.
Create a new template named blogdetails.html to display the complete Blog Post.
{% extends 'base.html' %}
{% block content %}
<div class="container mt-5">
<img src="{{ post.Image.url }}"
class="img-fluid rounded mb-4"
alt="{{ post.Title }}">
<span class="badge bg-primary">
{{ post.Category }}
</span>
<h2 class="mt-3">
{{ post.Title }}
</h2>
<p class="text-muted">
Published on {{ post.PublishDate }}
</p>
<hr>
{{ post.Description|safe }}
</div>
{% endblock %}
{{ post.Description|safe }}
CKEditor stores formatted HTML content in the database.
The safe filter tells Django to render the HTML instead of displaying it as plain text.
✓ Display QuerySets
✓ Bootstrap Card Layout
✓ Dynamic URLs using Slug
✓ get_object_or_404()
✓ Render CKEditor Content
✓ Dynamic Category Menu
Implement the same frontend functionality covered in today's Blog Project using your News Portal.