Introduction

Django is a free, open source web development framework of Python. Django's popularity is increasing day by day as it is written in Python programming language which is the most used language in the world.

Django is friendliness to both beginners and advanced programmers and suitable for developing from small-scale websites to large-scale websites.

Some of the popular sites using Django are Disqus, Instagram, Pinterest, Mozilla and many more.

Here, in this article we are going to create blog site application using django that beginners django developer should try to build before dive into the process of making complex django websites.

I assumed that you have little bit knowledge of Python language about its data structures and making functions.

Preview of Blog Application

how-create-blog-application-using-django

 

Requirements

Following requirements you need to run django in your operating system:

Python

As Django is written in pure python language, you have to install Python in your system from the link here.

If you have already installed python in your system, then you can headed to next steps.

 

Anaconda

Anaconda is an open source distribution of the Python and R programming languages developed by Anaconda, Inc. for scientific computing. It manages the python packages by creating separate conda environment for individual python projects.

Anaconda takes care of python packakges dependencies to each other packages and avoids packages collision.

For installing Anaconda follow the instructions given in the official site link here.

If you stuck in running django in conda environment, then you can refer to our previous articles on: How To Run Django in Conda Environment

Note: If you installed Anaconda, then you don't need to install python separately in your system. As python already comes within while installing Anaconda.

 

Tools Used

For creating a blog application, I am using following tools:

  • Pycharm as code editor
  • Python version 3.8.3
  • Django version 3.2 - LTS(Long Term Support) version
  • Windows 10 as operating system

 

Creating Virtual Environment

To create virtual environment using conda environment, first create new directory in one your local drive named 'django-blog'.

This is the directory where all django configurations files are stored from different apps to settings files.

D:\>mkdir django-blog

For easy to remember, I will be creating virtual environment name with the name of the directory 'django-blog' as:

D:\django-blog>conda create -n django-blog python==3.8.3

Hold on for seconds, as it installs necessary packages like python, pip, sqlite, wheel and others in the newly created virtual environment.

Then activate the environment using command:

D:\django-blog>conda activate django-blog

(django-blog) D:\django-blog>

Environment name inside parenthesis denotes that we successfully activated virtual envrionment for our project.

Note: If you don't want to use conda environment, then you can also create environment in this way. Here you don't have to install Anaconda but python should be installed in your system.

D:\django-blog>python -m venv django-blog

This command creates some files related to python libraries inside your working directory. For activating the environment use this command:

D:\django-blog>django-blog\Scripts\activate

 

Installing Django

We just created virtual envrionment named 'django-blog'. Now we install Django with pip inside this environment that treats Django as one of the package respect to other packages.

(django-blog) D:\django-blog>pip install Django

You can check the Django version installed in your project  bt using this command:

(django-blog) D:\django-blog>django-admin --version
3.2

 

Creating a new Django project

Let's create django project with the name 'blog_project' with the following command:

django-admin startproject blog_project .

Now if you run the development server with the command:

python manage.py runserver

You would see the page stating that the project is successfully running as shown in the following screenshot:

welcome-screen-django

 

Creating a blog application

As the one Django project consists of collection of apps that is created according to their specific functions. We are going to create 'blog' application that allows users to create, edit, and delete posts. 

python manage.py startapp blog

 

Activating blog application

We have to tell Django that we have created the application named 'blog' by adding its path blog.apps.BlogConfig to INSTALLED_APPS in settings.py file:

# blog_project/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    
    # local apps
    'blog.apps.BlogConfig',
]

 

Designing a database

For designing a database model of our blog application, we have to rough sketch what field that we should required in our application.

For simplicity to understand, we put only necessary fields like title, author, slug, body and published date without which blog cannot be complete.

If  you successfully created this application, then you should definitely make your appication more advanced by adding extra fields like status, tags and others.

Inside the models.py file of blog folder, define a new model called Post as:

# blog/models.py

from django.db import models
from django.urls import reverse
from django.utils import timezone
from django.contrib.auth.models import User


class Post(models.Model):
    title = models.CharField(max_length=250, unique=True)
    slug = models.SlugField(max_length=250,
                            unique=True)
    author = models.ForeignKey(User,
                               on_delete=models.CASCADE,
                               related_name='blog_posts')
    body = models.TextField()
    publish = models.DateTimeField(default=timezone.now)

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

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse('blog:blog_detail', args=[self.slug])

 

Fields explanation

  • tilte: This is the field for the post title and it is limiting to have maximum 250 characters and set to unique so that no any two blog posts can have same title.
  • slug: This field is used in the URL section. It is used to build beautiful, SEO-friendly URLs.
  • author: This field is set to determine who is the author of the blog post. If the particular user is deleted, then the posts written by him/her also deleted.
  • body: This is the field where author writes his/her contents related to the title of the post.
  • publish: This field indicates the published date of the blog post.
  • The Meta class inside the model contains metadata where we specify odering = ('-publish'). It denotes that whenever we query the Post model it retrieves the posts in descending order. Thus the recents posts appear first in the query result.
  • In __str__() method we return title of the post, to specify the particular post from number of posts by title in administration site, query object name and others.

 

Applying migrations

We designed model for our blog application in models.py. Now we have to create a new migration record for it and migrate the change into our database.

(django-blog) D:\django-blog>python manage.py makemigrations blog
(django-blog) D:\django-blog>python manage.py migrate

Cheers! We successfully configured our database.

 

Adding models to administration site

We have to add model to the administration site to appear it in the admin panel. If you do not add, then we do not see any models in the admin panel.

Go to the admin.py file of blog application and add following lines of code:

# blog/admin.py

from django.contrib import admin
from .models import Post

admin.site.register(Post)

 

Creating an administration site

Django administration site allows us to manage our blog posts. To enter into the Django admin panel, first we have to create a superuser account.

Superuser can have the authority of creating, editing and deleting blog posts i.e. have overall authority of managing the site like creating a new user and assigning permissions and others.

We can create superuser by running the command:

(django-blog) D:\django-blog>python manage.py createsuperuser
Username (leave blank to use 'codefires'): admin
Email address: [email protected]
Password: *******
Password (again): ******

Superuser created successfully.

Now start running the Django server again by the command python manage.py runserver and then open the link in your browser:

http://127.0.0.1:8000/admin/

django-admin-panel

 

Adding blog posts

Now let's add two three blog posts from the admin section so that we have sample of data to work with as:

add-post-blog-django

 

Working on views

We are going to use class-based views for displaying all posts and specific post through generic ListView and DetailView offered by Django. This base views allows to list objects of any kind.

Class-based views have more benefits over function-based views as we do not have to write all stuffs from scratch. Hence our time will be save and code looks more clear by using class-based views.

In the views.py file of blog application, create the two class-based views BlogListView and BlogDetailView as:

# blog/views.py

from django.views.generic import ListView, DetailView
from .models import Post


class BlogListView(ListView):
    model = Post
    context_object_name = 'posts'
    template_name = 'blog/blog_list.html'


class BlogDetailView(DetailView):
    model = Post
    context_object_name = 'post'
    template_name = 'blog/blog_detail.html'

What have we done above?

  • First we imported generic ListView and DetailView and Post model into views.py file of blog app.
  • Then we created two class-based views BlogListView and BlogDetailView.
  • We specified model = Post in both classes. It is same like calling post = Post.objects().all() in function-based views.
  • We used context variables: 'posts' for the BlogListView and 'post' for the BlogDetailView. The default variable is object_list if we don't specify any context_object_name.
  • At last specifying template_name that we are going to use for two class-based views. We will be creating those template in the next section inside the templates directory.

 

Adding url patterns for views

A URL pattern is composed of a string pattern, a view, and, optionally, a name that allows to name the URL project-wide. Thus URL patterns allow to map URLs to views.

Create a urls.py file inside the blog application directory as:

(django-blog) D:\django-blog>cd blog

(django-blog) D:\django-blog\blog>type nul> urls.py

Then inside the urls.py file add the following lines of code:

# blog/urls.py

from django.urls import path
from .views import BlogListView, BlogDetailView

app_name = 'blog'

urlpatterns = [
    # post views
    path('', BlogListView.as_view(), name='blog_list'),
    path('<slug:slug>/', BlogDetailView.as_view(), name='blog_detail'),

]

After that, we have to include the URL patterns of the blog application in the main URL patterns of the project.

For that simply edit the main urls.py file inside the blog_project directory as:

# blog_project/urls.py 

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

urlpatterns = [
    path('admin/', admin.site.urls),
    # add this line
    path('', include('blog.urls', namespace='blog')),
]

Till now, we have done our backend part, now left work is frontend part that consists of HTML, CSS and Javascript codes.

 

Creating templates for views

Let's create a project-level directory called templates(on working directory) and inside that directory create one base.html file and another blog direcotory. Your file structure should look like this:

templates/
     base.html
     blog/
         blog_list.html
         blog_detail.html

Why base.html needed?

base.html is the file that includes the main HTML structure of the website and divide the content into the main content, header, footer and sidebar. So that other templates do not need to implement the same header, footer in each page.

The blog_list.html and blog_detail.html will simply inherit from the base.html following DRY principle(Do not Repeat Yourself).

Now we have to update TEMPLATES section of settings.py file with the following code so that Django knows to look there for our templates.

blog_project/settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR / 'templates'],
        # for django version < 3.1
        # using os module
        # 'DIRS': [os.path.join(BASE_DIR, 'templates')],

        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

 

Bootstrap as CSS framework

In our templates, we are going to use frontend CSS framework called Bootstrap that takes care all our frontend parts keeping templates both desktop and mobile friendly.

For using Bootstrap, we just have to use the starter template from the link here and embed it into the base.html file as shown below:

base.html

<!--templates/base.html-->

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
          integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous">

    <title>Building Blog in Django</title>
</head>
<body>

<!--  header starts here-->
<header>
    <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
        <a class="navbar-brand" href="#">CodeFires</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
                aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarSupportedContent">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item active">
                    <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="#">Blog</a>
                </li>
            </ul>
            <form class="form-inline my-2 my-lg-0">
                <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
                <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
            </form>
        </div>
    </nav>
</header>
<!--  header ends here-->

<!--main container starts here-->
<div class="container my-4">
    {% block container %}
    {% endblock %}

</div>


<!-- jQuery and Bootstrap Bundle (includes Popper) -->
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns"
        crossorigin="anonymous"></script>

</body>
</html>

 

blog_list.html

<!--templates/blog/blog_list.html-->

{% extends 'base.html' %}

{% block container %}

<div class="row">
    {% for post in posts %}
    <div class="col-sm-6 mt-4">
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">{{ post.title }}</h5>
                <p class="card-text">{{ post.body | truncatechars:50 }}</p>
                <a href="{{ post.get_absolute_url }}" class="btn btn-primary">Read more</a>
            </div>
        </div>
    </div>
    {% endfor %}

</div>

{% endblock %}

 

blog_detail.html

<!--templates/blog/blog_detail.html-->

{% extends 'base.html' %}

{% block container %}

<div class="row">
    <div class="card">
        <h5 class="card-header">{{ post.title }} by <span class="text-primary">{{ post.author }}</span></h5>
        <div class="card-body">
            <h5 class="card-title">Published: {{ post.publish }}</h5>
            <p class="card-text">{{ post.body }}</p>
        </div>
    </div>

</div>

{% endblock %}

We have finally completed templates section also by adding two html files named blog_list.html for displaying all blog posts and another blog_detail.html for displaying detail view of blog post whenever the user of the site click Read more button from the list of posts.

Note: In above both the templates blog_list.html and blog_detail.html, we have inherit base.html so that we do not have to add header and footer. Using the code of line {% extends 'base.html' %} we can inherit the properties in any html files.

 

Run the django server

Now to see the output you have to run the Django server from the terminal using the command python manage.py runserver and then open the url http://127.0.0.1:8000 in your browser.

Screenshots of the outputs are shown below:

blog-list-django

blog-detail-django

 

Conclusion

Excellent we did it, we completed our blog application using Django. We come across various new terms related to Django and we pretty deal with them in an effective way by understanding clearly.

I hope you learn the basic concepts of developing blog site from this article. If you stuck in any area then do not forget to comment down below. I will be hearing your message as soon as possible.

Also do not forget to enhance this blog application by adding advanced features like comment system, sharing systems in near future. The best way to learn any programming language is just by doing the real projects.

For reference of this blog project, you can refer to this Github repository!

Happy Learning :-)