In this tutorial series, we are going to take a big step on our web development journey by creating a blog application using the Django web framework. We will design the application in such a way that the user can create, edit and delete posts.
Having completed the portfolio website project, I expect you to have, among other things, a basic knowledge of Django as this project is going to be a little bit advanced. This is just to speed up your learning process. But if you are just starting to learn Django, you can still follow along with my thorough explanation.
This blog application will span more than three series as we add more advanced features such as comments, images, a rich text editor, pagination, and so much more.
💡 Part 2: How I Created a Blog Application Using Django – Part 2
Getting Started

We won’t spend much time in this section. Just follow the instructions on your Ubuntu terminal to get your system ready for this project.
Step 1: Create a new directory called django_project
mkdir django_project && cd django_project
Step 2: Install Django in a virtual environment
python3 -m venv .venv source .venv/bin/activate pip install django tzdata django-admin startproject project . python3 manage.py startapp blog
Step 3: Perform a migration
python3 manage.py migrate
Step 4: Register the app in the project’s settings.
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # custom app 'blog', ]
The Database Model

A database is queried using a programming language other than Python. If you are not comfortable with Structured Query Language (SQL), working with databases can be a big challenge.
Django got us covered with its Object Relation Mapper (ORM) which turns model classes into a database table. So, all we need to do is to define the classes and Django will do the rest.
Go to blog/models.py
file and add this:
from django.db import models from django.contrib.auth.models import User from django.urls import reverse STATUS = ( ( 0, 'Draft'), (1, 'Publish') ) class Category(models.Model): name = models.CharField(max_length=20) def __str__(self): return self.name class Post(models.Model): author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts') title = models.CharField(max_length=255, unique=True) body = models.TextField() slug = models.SlugField(max_length=255, unique=True) created_on = models.DateTimeField(auto_now_add=True) last_modified = models.DateTimeField(auto_now=True) categories = models.ManyToManyField('Category', related_name='posts') status = models.IntegerField(choices=STATUS, default=0) class Meta: ordering = ['-created_on'] def __str__(self): return self.title def get_absolute_url(self): return reverse('blog_detail.html', kwargs=({'slug': self.slug}))
On the top, we import the models
module that will be used to create tables and their fields; the User
model to handle user accounts and authentication, and the reverse()
function to generate URLs.
We then create two classes that inherit the model.Model
class. Our models become a subclass of models.Model
. This is done on all models created with Django.
The Category
class or model is needed to store the name of the category of a post. The CharField
is used because we only want short strings as indicated by the limited number of text defined. This was also the case for the title in Post
model.
The SlugField
enables us to add slugs to our blog. To understand what a slug is and how it works, this detailed article comes in handy. Both the slug and the title have an argument, unique=True
. This tells Django not to accept any duplicated strings. The TextField
is for long text. In this field, we will write our blog content.
The DateTimeField
is self-explanatory but it has an argument, auto_now_add=True
. What this means is that whenever an instance of the Post
class is created, the current date and time is assigned to this field. The argument, auto_now=True
does something similar but only when an instance of the Post
class is saved. So, when you make some adjustments to the blog post, the last_modified
is updated.
The author field uses a ForeignKey
. This allows for a many-to-one relationship. That is, for a given user to be the author of many different blog posts. This many-to-one relationship has an on_delete
option set to CASCADE
.
What this means is that when a user is deleted, we don’t want the blog post related to the user hanging around. We want them deleted as well. The related_name
argument makes it easy to access a list of posts by a given user using author.blog_posts
.
The ManyToManyField
allows for a many-to-many relationship. It is in this field that we link the two model classes in such a way that many categories can be assigned to many posts.
Notice that there is a tuple named STATUS
defined to separate drafts from published posts. This was done in the status
field.
The Post
model has a Meta
class. This tells Django to store post in descending order (as shown by the negative prefix) based on the created_on
field. The __str__
method is used to represent the class object in a human-readable form.
The get_absolute_url
method returns a URL it builds using the reverse
function.
Having created the database, let’s create the migration files with the makemigrations
command. Then we migrate the tables.
python3 manage.py makemigrations blog python3 manage.py migrate
Creating an Admin Panel

Django has an inbuilt admin interface to create and manage the Post
model. To use the admin panel, we have to create a superuser account. Run the following command and follow the instructions therein. Remember that the password is not visible on the terminal.
python3 manage.py createsuperuser
Start the local with the following command and go to http://127.0.0.1/admin
in your browser.
python3 manage.py runserver
Once you log in, you will see the admin panel. But our Post
model is nowhere to be found. That’s because we have not registered our model. So, let’s do so in the admin.py
file located in the blog folder.
from django.contrib import admin from .models import Post, Category class PostAdmin(admin.ModelAdmin): list_display = ('title', 'slug', 'status', 'created_on',) list_filter = ('status',) search_fields = ['title', 'body'] prepopulated_fields = {'slug': ('title',)} admin.site.register(Post, PostAdmin) admin.site.register(Category)
We customize the way data is displayed to make the admin more efficient.
The prepopulated_fields
automatically generate the value for the slug
field using the title
field. Without setting this, adding a slug becomes tedious. With this in place, once we type the name of the blog article, the slug
field is automatically populated.
The search_fields
sets which attributes to search for in the database. The list_filter
filters the post based on the status
field.
Now everything is set, open the admin once again and add blog articles to it.

We can see everything we customized is displayed. The code for this first series is on my GitHub page.
🧑💻 Recommended: How I Built a QR Code Generator in Django Web Application
Conclusion
So far in this project on creating a blog application, we have set up Django in our system, created our models and customized the admin interface. No doubt, the models will take you a lot of time to digest especially if you are a beginner. Well, you have all the time you need.
In the second part series, we will continue from where we stopped by creating the views, mapping the URLs to the views, and setting the templates to display the blog articles. 👇👇👇
💡 Part 2: How I Created a Blog Application Using Django – Part 2

Jonathan Okah is a professional freelance Python developer whose primary goal is to solve a perceived problem with the use of technology, thus making life easy for you.
He has basic knowledge of Python, C, JavaScript, HTML, CSS and R, but has taken his knowledge of Python to the next level at Upwork, where he performs services for clients.
Jonathan has a flair for writing and has written several blog articles for clients. He is constantly learning to improve his skills. Currently, he is studying software engineering, hoping to become a full-stack web developer.
In his leisure time, Jonathan enjoys playing games and watching the English Premier League. You can contact him for your freelance projects at Upwork.