How To Create Django Blog Step By Step Tutorial

How To Create Django Blog Step By Step Tutorial

Django Blog Tutorial with no script

how I build a simple Django blog from scratch. For the front-end, I use Tailwind to make it look great.

In this tutorial, we’ll build a Blog application with Django

Pre-Requirements

Django is an open-source web framework, written in Python, that follows the model-view-template architectural pattern. So Python is needed to be installed in your machine. Unfortunately, there was a significant update to Python several years ago that created a big split between Python versions namely Python 2 the legacy version and Python 3 the version in active development.

Since Python 3 is the current version in active development and addressed as the future of Python, Django rolled out a significant update, and now all the releases after Django 2.0 are only compatible with Python 3.x. Therefore this tutorial is strictly for Python 3.x. Make sure you have Python 3 installed on your machine if not follow the below guides.

Creating And Activating A Virtual Environment

While building python projects, it's a good practice to work in virtual environments to keep your project, and it's dependency isolated on your machine.

python3 -m venv env

Installing Django In The Virtual Environment

If you have already installed Django, you can skip this section and jump straight to the Setting up the project section. To Install Django on your virtual environment run the below command

pip install Django

Setting Up The Project

In your workspace create a new folder and activate your virtual environment

Now run the following command in your shell to create a Django project.

django-admin startproject myblog
cd myblog

Next, make migrations.

python manage.py migrate

Create Super User

python manage.py createsuperuser

Set username and password for admin dashboard

Create App

python manage.py startapp post

And open settings.py file and add post

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'post',
]

Now Create Two Folder inside of post, templates and create second folder inside of templates folder post . and open models.py file and write this code

from statistics import mode
from django.db import models

class Category(models.Model):
    title = models.CharField(max_length=255)

    def __str__(self):
        return self.title

class Post(models.Model):
    category = models.ForeignKey(Category, related_name='posts', on_delete=models.CASCADE)
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255)
    intro = models.TextField()
    body = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ('-created_at', )

    def __str__(self):
        return self.title

Save and update the database using this commands

python manage.py makemigrations
python .\manage.py migrate

after complete migrations open admin.py file and write this code

from django.contrib import admin
from .models import Post, Category

admin.site.register(Category)
admin.site.register(Post)

let's run the server python manage.py runserver and open /admin login and create a new category and post for testing, after creating post let's open templates/post and create base.html file and write this code

<!doctype html>

<html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <script src="https://cdn.tailwindcss.com"></script>
    </head>

    <body>
        <nav class="py-6 px-8 bg-gray-800 text-white">
            <a href="/">X Blog</a>
        </nav>

        <main class="py-6 px-8">
            {% block content %}
            {% endblock %}
        </main>

        <footer class="py-8 px-8 bg-gray-800 text-gray-400">
            <p class="text-xs">Copyright 2022 - Acoderr</p>
        </footer>
    </body>
</html>

after write the code create one more file frontpage.html and open past this code

{% extends 'post/base.html' %}

{% block content %}
<div class="space-y-4">
    {% for post in posts %}
    <article class="p-6 bg-gray-100 rounded-xl">
        <h2 class="text-3xl">{{ post.title }}</h2>

        <span class="mb-4 block text-xs text-gray-600">{{ post.created_at }}</span>

        <p class="mb-6">{{ post.intro }}</p>

        <a href="{% url 'post_detail' post.slug %}" class="text-emerald-500">Read more</a>
    </article>
    {% endfor %}
</div>
{% endblock %}

and open views.py file and past this code

from django.shortcuts import render, get_object_or_404, redirect
from .models import Post

def frontpage(request):
    posts = Post.objects.all()

    return render(request, 'post/frontpage.html', {'posts': posts})

def post_detail(request, slug):
    post = get_object_or_404(Post, slug=slug)

    return render(request, 'post/detail.html', {'post': post})

open urls.py add this path

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

from post import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.frontpage, name='frontpage'),
    path('<slug:slug>/', views.post_detail, name='post_detail'),
]

let's create detail.html file inside of templates/post folder and past this code

{% extends 'post/base.html' %}

{% block content %}
<article class="p-6 bg-gray-100 rounded-xl">
        <h2 class="text-3xl">{{ post.title }}</h2>

        <span class="mb-4 block text-xs text-gray-600">{{ post.category.title }} | {{ post.created_at }}</span>

        <p class="mb-6 font-semibold">{{ post.intro }}</p>

        <p class="text-gray-800">
            {{ post.body }}
        </p>

    </article>

  <div class="mt-4 p-6 bg-gray-100 rounded-xl">
        <h3 class="mb-4 text-xl">Comments</h3>

        {% for comment in post.comments.all %}
            <div class="mb-4 w-full py-4 px-6 rounded-xl bg-white">
                <strong>{{ comment.name }}</strong> | {{ comment.created_at|timesince }} ago<br>

                <p class="text-gray-500">{{ comment.comment }}</p>
            </div>
        {% endfor %}

        <h3 class="mb-4 text-xl">Add new comment</h3>

        <form method="post" action="." class="space-y-4">
            {% csrf_token %}

            <div>
                <label>Name</label><br>
                <input type="text" name="name" class="w-full py-4 px-6 rounded-xl bg-white">
            </div>

            <div>
                <label>E-mail</label><br>
                <input type="email" name="email" class="w-full py-4 px-6 rounded-xl bg-white">
            </div>

            <div>
                <label>Comment</label><br>
                <textarea name="comment" class="w-full py-4 px-6 rounded-xl bg-white"></textarea>
            </div>

            <div>
                <button class="py-4 px-6 rounded-xl bg-emerald-800 text-white">Submit</button>
            </div>
        </form>
    </div>

{% endblock %}

open models.py file add this

class Comment(models.Model):
    post = models.ForeignKey(Post, related_name='comments', on_delete=models.CASCADE)
    name = models.CharField(max_length=255)
    email = models.EmailField(max_length=255)
    comment = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

save this and open views.py and remove all code and add this code

from django.shortcuts import render, get_object_or_404, redirect
from .models import Post, Comment

def frontpage(request):
    posts = Post.objects.all()

    return render(request, 'post/frontpage.html', {'posts': posts})

def post_detail(request, slug):
    post = get_object_or_404(Post, slug=slug)

    if request.method == 'POST':
        name = request.POST.get('name', '')
        comment = request.POST.get('comment', '')

        if name and comment:
            Comment.objects.create(
                post=post,
                name=name,
                comment=comment
            )

            return redirect('post_detail', slug=post.slug)

    return render(request, 'post/detail.html', {'post': post})

Save and update the database using this commands

python manage.py makemigrations
python .\manage.py migrate

and run the server to check its work fine or not

Add Category

so open detail.html file and replace this code to this

<span class="mb-4 block text-xs text-gray-600"> <a href="{% url 'category_detail' post.category.id %}">{{ post.category.title }}</a> | {{ post.created_at }}</span>

open views.py and add this code

from .models import Post, Comment, Category

def category_detail(request, pk):
    category = get_object_or_404(Category, pk=pk)

    return render(request, 'post/category.html', {'category': category})

and open urls.py and add this path

path('categories/<int:pk>/', views.category_detail, name='category_detail'),

let's create category.html file inside of templates/post folder and past this code

{% extends 'post/base.html' %}

{% block content %}
<div class="space-y-4">
    <h1 class="text-3xl">{{ category.title }}</h1>

    {% for post in category.posts.all %}
        <article class="p-6 bg-gray-100 rounded-xl">
            <h2 class="text-3xl">{{ post.title }}</h2>

            <span class="mb-4 block text-xs text-gray-600">{{ post.created_at }}</span>

            <p class="mb-6">{{ post.intro }}</p>

            <a href="{% url 'post_detail' post.slug %}" class="text-emerald-500">Read more</a>
        </article>
    {% endfor %}
</div>
{% endblock %}

Save and update the database using this commands

python manage.py makemigrations
python .\manage.py migrate

and run the server

Demo

Now visit the homepage and click on read more, it should redirect you to the post detail page.

ezgif-2-2693c69d22.gif

Wrapping It Up

We have come to the end of this tutorial. Thank you for reading this far. This post is just the tip of the iceberg considering the number of things you could do with Django.

We have built a basic blog application from scratch! Using the Django

If you are stuck at any step, refer to this GitHub repo

This blogging app should be enough to get you started with Django.

Did you find this article valuable?

Support Amit Gajare by becoming a sponsor. Any amount is appreciated!