Lesson 56 of 60 – Django Blog Project
93%

Django Blog Project

In this lesson, we will build a practical Django Blog Project. A blog is an excellent project for understanding how models, forms, templates, views, URLs, CRUD operations, authentication, search, and pagination work together in a real Django application.

Our basic blog system will allow users to create posts, view posts, edit posts, delete posts, search posts, and display posts with pagination.

Note: This is a learning project. You can later extend it with comments, categories, tags, user profiles, image uploads, likes, and other features.

1. What is a Blog Project?

A blog is a website where users can publish and read articles or posts.

A basic blog can contain:

  • Blog title
  • Blog content
  • Author
  • Publication date
  • Updated date
  • Post status

2. Main Features of the Blog

Our Django blog project can contain the following features:

  • Create blog posts
  • Display blog posts
  • View individual posts
  • Edit posts
  • Delete posts
  • Search posts
  • Pagination
  • User authentication
  • Admin management
  • Success messages

3. Create the Django Project

Create a new Django project:

django-admin startproject blog_project

Move into the project:

cd blog_project

Start the development server:

python manage.py runserver

4. Create the Blog App

Create an application named blog.

python manage.py startapp blog

Add it to INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    "blog",
]

5. Create the Blog Post Model

The Post model will store blog information.

from django.db import models

class Post(models.Model):

    title = models.CharField(
        max_length=200
    )

    content = models.TextField()

    author = models.CharField(
        max_length=100
    )

    created_at = models.DateTimeField(
        auto_now_add=True
    )

    updated_at = models.DateTimeField(
        auto_now=True
    )

    def __str__(self):
        return self.title

6. Run Blog Migrations

Create the migration:

python manage.py makemigrations

Apply the migration:

python manage.py migrate

Django will create the database table for blog posts.

7. Create a Blog ModelForm

Create blog/forms.py.

from django import forms
from .models import Post

class PostForm(forms.ModelForm):

    class Meta:

        model = Post

        fields = [
            "title",
            "content",
            "author"
        ]

The ModelForm generates form fields from the Post model.

8. Create Blog List View

The list view retrieves all blog posts.

from django.shortcuts import render
from .models import Post

def post_list(request):

    posts = Post.objects.all().order_by(
        "-created_at"
    )

    return render(
        request,
        "blog/post_list.html",
        {
            "posts": posts
        }
    )

The newest posts are displayed first.

9. Create Blog List Template

Create post_list.html.

<h1>Latest Blog Posts</h1>

{% for post in posts %}

    <article>

        <h2>
            {{ post.title }}
        </h2>

        <p>
            By {{ post.author }}
        </p>

        <p>
            {{ post.content|truncatewords:30 }}
        </p>

        <a href="{% url 'post_detail' post.id %}">
            Read More
        </a>

    </article>

{% empty %}

    <p>
        No blog posts available.
    </p>

{% endfor %}

10. Create Blog Detail View

The detail view displays one complete blog post.

from django.shortcuts import get_object_or_404

def post_detail(request, id):

    post = get_object_or_404(
        Post,
        id=id
    )

    return render(
        request,
        "blog/post_detail.html",
        {
            "post": post
        }
    )

11. Blog Detail Template

<article>

    <h1>
        {{ post.title }}
    </h1>

    <p>
        By {{ post.author }}
    </p>

    <p>
        Published:
        {{ post.created_at }}
    </p>

    <div>
        {{ post.content|linebreaks }}
    </div>

</article>

12. Create Blog Post View

The create view allows a user to add a new blog post.

from django.shortcuts import redirect
from .forms import PostForm

def post_create(request):

    if request.method == "POST":

        form = PostForm(
            request.POST
        )

        if form.is_valid():

            form.save()

            return redirect(
                "post_list"
            )

    else:

        form = PostForm()

    return render(
        request,
        "blog/post_form.html",
        {
            "form": form
        }
    )

13. Blog Post Form Template

<h2>
Create Blog Post
</h2>

<form method="post">

    {% csrf_token %}

    {{ form.as_p }}

    <button
        type="submit"
    >
        Publish Post
    </button>

</form>

The CSRF token should be included in POST forms.

14. Update Blog Post

The same ModelForm can be used to edit an existing post.

def post_update(request, id):

    post = get_object_or_404(
        Post,
        id=id
    )

    if request.method == "POST":

        form = PostForm(
            request.POST,
            instance=post
        )

        if form.is_valid():

            form.save()

            return redirect(
                "post_detail",
                id=post.id
            )

    else:

        form = PostForm(
            instance=post
        )

    return render(
        request,
        "blog/post_form.html",
        {
            "form": form,
            "post": post
        }
    )

15. Delete Blog Post

The delete view removes an existing blog post.

def post_delete(request, id):

    post = get_object_or_404(
        Post,
        id=id
    )

    if request.method == "POST":

        post.delete()

        return redirect(
            "post_list"
        )

    return render(
        request,
        "blog/post_confirm_delete.html",
        {
            "post": post
        }
    )

16. Delete Confirmation Template

<h2>
Delete Blog Post
</h2>

<p>
Are you sure you want to delete
"{{ post.title }}"?
</p>

<form method="post">

    {% csrf_token %}

    <button
        type="submit"
    >
        Yes, Delete
    </button>

</form>

<a href="{% url 'post_detail' post.id %}">
    Cancel
</a>

17. Blog URL Patterns

Create blog/urls.py.

from django.urls import path
from . import views

urlpatterns = [

    path(
        "",
        views.post_list,
        name="post_list"
    ),

    path(
        "create/",
        views.post_create,
        name="post_create"
    ),

    path(
        "<int:id>/",
        views.post_detail,
        name="post_detail"
    ),

    path(
        "<int:id>/edit/",
        views.post_update,
        name="post_update"
    ),

    path(
        "<int:id>/delete/",
        views.post_delete,
        name="post_delete"
    ),

]

18. Include Blog URLs

Include the blog URLs in the project's main urls.py.

from django.contrib import admin
from django.urls import path, include

urlpatterns = [

    path(
        "admin/",
        admin.site.urls
    ),

    path(
        "",
        include("blog.urls")
    ),

]

The blog homepage can now be accessed from the root URL.

19. Add Search to the Blog

Users can search blog posts by title.

query = request.GET.get(
    "q",
    ""
).strip()

posts = Post.objects.all()

if query:

    posts = posts.filter(
        title__icontains=query
    )

posts = posts.order_by(
    "-created_at"
)

20. Blog Search Form

<form method="get">

    <input
        type="text"
        name="q"
        value="{{ query }}"
        placeholder="Search posts"
    >

    <button
        type="submit"
    >
        Search
    </button>

</form>

The search value is sent as a GET parameter.

21. Add Pagination to Blog

Pagination is useful when a blog contains many posts.

from django.core.paginator import Paginator

paginator = Paginator(
    posts,
    5
)

page_number = request.GET.get(
    "page"
)

page_obj = paginator.get_page(
    page_number
)

Here, five blog posts are displayed per page.

22. Pagination Navigation

{% if page_obj.has_previous %}

    <a href="?q={{ query }}&page={{
        page_obj.previous_page_number
    }}">

        Previous
    </a>

{% endif %}

<span>

    Page {{ page_obj.number }}
    of
    {{ page_obj.paginator.num_pages }}

</span>

{% if page_obj.has_next %}

    <a href="?q={{ query }}&page={{
        page_obj.next_page_number
    }}">

        Next
    </a>

{% endif %}

23. Add Messages

Messages can inform users when posts are created, updated, or deleted.

from django.contrib import messages

form.save()

messages.success(
    request,
    "Blog post published successfully."
)

return redirect(
    "post_list"
)

Messages can also be added after update and delete operations.

24. Register Post in Admin

Register the Post model in blog/admin.py.

from django.contrib import admin
from .models import Post

@admin.register(Post)
class PostAdmin(admin.ModelAdmin):

    list_display = (
        "title",
        "author",
        "created_at",
        "updated_at"
    )

    search_fields = (
        "title",
        "content",
        "author"
    )

    ordering = (
        "-created_at",
    )

25. Protect Blog Management with Login

Only authenticated users may be allowed to create, edit, or delete posts.

from django.contrib.auth.decorators import login_required

@login_required
def post_create(request):

    if request.method == "POST":

        form = PostForm(
            request.POST
        )

        if form.is_valid():

            form.save()

            return redirect(
                "post_list"
            )

    else:

        form = PostForm()

    return render(
        request,
        "blog/post_form.html",
        {
            "form": form
        }
    )

26. Suggested Blog Project Structure

blog_project/
│
├── manage.py
│
├── blog_project/
│   ├── settings.py
│   ├── urls.py
│   ├── asgi.py
│   └── wsgi.py
│
└── blog/
    ├── migrations/
    ├── templates/
    │   └── blog/
    │       ├── post_list.html
    │       ├── post_detail.html
    │       ├── post_form.html
    │       └── post_confirm_delete.html
    │
    ├── __init__.py
    ├── admin.py
    ├── apps.py
    ├── forms.py
    ├── models.py
    ├── urls.py
    ├── views.py
    └── tests.py

27. Complete Blog List View

from django.shortcuts import render
from django.core.paginator import Paginator
from .models import Post

def post_list(request):

    query = request.GET.get(
        "q",
        ""
    ).strip()

    posts = Post.objects.all()

    if query:

        posts = posts.filter(
            title__icontains=query
        )

    posts = posts.order_by(
        "-created_at"
    )

    paginator = Paginator(
        posts,
        5
    )

    page_number = request.GET.get(
        "page"
    )

    page_obj = paginator.get_page(
        page_number
    )

    return render(
        request,
        "blog/post_list.html",
        {
            "page_obj": page_obj,
            "query": query
        }
    )

28. Blog Project Workflow

Blog Model
     ↓
Database Migration
     ↓
ModelForm
     ↓
Create Post
     ↓
List Posts
     ↓
View Post
     ↓
Edit Post
     ↓
Delete Post
     ↓
Search Posts
     ↓
Pagination
     ↓
Authentication
     ↓
Admin Panel

These components work together to create a complete basic blog application.

29. Future Blog Features

The basic blog can be extended with many advanced features.

  • User registration and login
  • Author profiles
  • Post categories
  • Post tags
  • Comments
  • Post images
  • Featured posts
  • Draft and published status
  • Likes
  • Social sharing
  • Related posts
  • SEO-friendly URLs

30. Django Blog Project Summary

The Django Blog Project combines many concepts learned throughout the Django tutorial into one practical application.

  • Use Models to store blog posts.
  • Use ModelForms to create and update posts.
  • Use Views to implement blog logic.
  • Use URLs to connect requests with views.
  • Use Templates to display blog content.
  • Use CRUD operations to manage posts.
  • Use Search to find posts.
  • Use Pagination for large numbers of posts.
  • Use Authentication to protect management operations.
  • Use Django Admin to manage blog content.

📌 Key Points

  • A Django blog is a practical project for learning Django.
  • The Post model stores blog information.
  • ModelForm simplifies post creation and editing.
  • CRUD operations manage blog posts.
  • Search helps users find posts.
  • Pagination handles large numbers of posts.
  • Authentication can protect blog management pages.
  • Django Admin provides another way to manage posts.

🧠 Quick Quiz

Question: Which Django component is commonly used to create a form directly from the Blog Post model?