Before doing this tutorial, make sure you finish part one, part two and part three.
First we will make all folders and file that needed. Open the “myblog/” folder on your Visual Studio Code. You can do this manually by opening the Visual Studio Code first.
Go to root folder which is myblog, create a folder named “templates”. Inside this folder “templates”, create a HTML file named “base.html”.
Go to folder “myblog/blog” and create a python file named “urls.py”.
Go to folder “myblog/blog” and add two folders named “templates” and “static”.
Inside folder “myblog/blog/templates” create three HTML files named “blog_index.html”, “blog_details.html”, and “blog_category.html”.
Inside folder “myblog/blog/static” put an image that will be our site logo.

Open file “myblog/templates/base.html”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}My Personal Website{% endblock title %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<header>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand p-3" href="{% url 'blog_index' %}">
{% load static %}
<img src="{% static 'site-logo.png' %}" width="32" height="32">
</a>
</div>
</nav>
</header>
<main>
{% block page_content %}
{% endblock page_content %}
</main>
<footer class="align-items-center text-center my-5 mx-2">
<span class="text-center">Copyright 2025, made by Django</span>
</footer>
</body>
</html>
Open file “myblog/blog/views.py”
from django.template import loader
from django.http import HttpResponse
from .models import Post, Category
def blog_index(request):
template = loader.get_template('blog_index.html')
posts = Post.objects.all()
context = {
"posts" : posts
}
return HttpResponse(template.render(context))
Open file “myblog/blog/templates/blog_index.html”
{% extends "base.html" %}
{% block page_content %}
<section class="container my-5">
{% block page_title %}<h1>Blog Posts</h1>{% endblock page_title %}
<div class="row">
{% block posts %}
{% for post in posts %}
<div class="col-md-12">
<div class="card mb-4 box-shadow">
<div class="card-body">
<p class="card-text">{{ post.title }}</p>
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">{{ post.created_on.date }}</small>
<div class="btn-group">
<a type="button" class="btn btn-sm btn-outline-secondary" href="#">Read More</a>
</div>
</div>
</div>
</div>
</div><!--col-md-4-->
{% endfor %}
{% endblock posts %}
</div>
</section>
{% endblock page_content %}
Open file “myblog/blogproject/settings.py”.
On the “TEMPLATES” array and inside “DIRS” add “BASE_DIR / templates”. This addition will make sure Django see all our templates folder and files inside it.

Still inside file “myblog/blogproject/settings.py”, search for section about Static Files. Write these codes on it. It is defining STATIC_URL, STATIC_FILE_FINDERS, STATICFILES_DIR.

Open file “myblog/blog/urls.py”
from django.urls import path
from . import views
urlpatterns = [
path('', views.blog_index, name="blog_index")
]
Open file “myblog/blogproject/urls.py”
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("blog.urls"))
]
Let see what is our current output by running the server.

This is our progress of the blog website. On top left you can see your site logo and it can be clicked to open the index page which is blog_index.html. On the page body you can see all your posts listed in a card style. Each post display post title, post created_on date, and a read more button. Our read more button do nothing right now and we will change it soon.
What we want is when the read more button click it redirect to details of that post. In order to do this, we need to write file blog_details.html and change files urls.py and views.py.
Open file “myblog/blog/views.py”. We add a new function named “blog_details” and “blog_category”.
from django.template import loader
from django.http import HttpResponse
from .models import Post, Category
def blog_index(request):
template = loader.get_template('blog_index.html')
posts = Post.objects.all()
context = {
"posts" : posts
}
return HttpResponse(template.render(context))
def blog_details(request, pk):
template = loader.get_template('blog_details.html')
post = Post.objects.get(pk=pk)
context = {
"post" : post
}
return HttpResponse(template.render(context))
def blog_category(request, category):
template = loader.get_template('blog_category.html')
posts = Post.objects.filter(
categories__name__contains=category
).order_by("-created_on")
context = {
"category": category,
"posts": posts,
}
return HttpResponse(template.render(context))
Open file “myblog/blog/urls.py” add modify the file.
from django.urls import path
from . import views
urlpatterns = [
path('', views.blog_index, name="blog_index"),
path('post/<int:pk>/', views.blog_details, name='blog_details'),
path("category/<category>/", views.blog_category, name="blog_category"),
]
Open file “myblog/blog/templates/blog_index.html”. See on the read more button we add complete href url.
{% extends "base.html" %}
{% block page_content %}
<section class="container my-5">
{% block page_title %}<h1>Blog Posts</h1>{% endblock page_title %}
<div class="row">
{% block posts %}
{% for post in posts %}
<div class="col-md-12">
<div class="card mb-4 box-shadow">
<div class="card-body">
<p class="card-text">{{ post.title }}</p>
<div class="d-flex justify-content-between align-items-center">
<small class="text-muted">{{ post.created_on.date }}</small>
<div class="btn-group">
<a type="button" class="btn btn-sm btn-outline-secondary" href="{% url 'blog_details' post.pk %}">Read More</a>
</div>
</div>
</div>
</div>
</div><!--col-md-4-->
{% endfor %}
{% endblock posts %}
</div>
</section>
{% endblock page_content %}
Open file “myblog/blog/templates/blog_details.html”
{% extends "base.html" %}
{% block page_content %}
<div class="container-md my-5">
{% block post %}
<article class="blog-post">
<h2 class="blog-post-title mb-1">{{ post.title }}</h2>
<p class="blog-post-meta">{{ post.created_on.date }}</p>
{% for category in post.categories.all %}
<small class="px-1">
<a href="{% url 'blog_category' category.name %}"> {{ category.name }} </a>
</small>
{% endfor %}
<div class="post-body my-4">
{{post.body}}
</div>
</article>
{% endblock post %}
</div>
{% endblock page_content %}
Open file “myblog/blog/templates/blog_category.html”
{% extends "blog_index.html" %}
{% block page_title %}
<a class="btn btn-sm btn-outline-secondary mb-4" href="{% url 'blog_index' %}">All Blog Posts</a>
<h2>Post category: {{ category }}</h2>
{% endblock page_title %}
What we have done so far!!!
Oh, lets add text editor and ability to displayed HTML on our Post. Check out Part 5.