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 friendly to both beginners and advanced programmers and is 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 a blog site application using Django that beginner Django developers should try to build before diving into the process of making complex Django websites.
I assumed that you have a little bit of knowledge of Python language about its data structures and making functions.
Preview of Blog Application
Requirements
Following the 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 head to the 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 a separate conda environment for individual python projects.
Anaconda takes care of python packages’ dependencies on each other packages and avoids package collision.
For installing Anaconda follow the instructions given in the official site link here.
If you are stuck in running Django in a 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 the following tools:
- PyCharm as code editor
- Python version 3.8.3
- Django version 3.2 – LTS(Long Term Support) version
- Windows 10 as the operating system
Creating Virtual Environment
To create a virtual environment using conda environment, first create a new directory in one of your local drives named ‘django-blog’.
This is the directory where all Django configuration files are stored from different apps to settings files.
D:\>mkdir django-blog
For easy to remember, I will be creating a 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 the command:
D:\django-blog>conda activate django-blog (django-blog) D:\django-blog>
The environment name inside the parenthesis denotes that we successfully activated the virtual environment for our project.
Note: If you don’t want to use a conda environment, then you can also create an 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 a virtual environment named ‘django-blog’. Now we install Django with pip inside this environment that treats Django as one of the packages with respect to other packages.
(django-blog) D:\django-blog>pip install Django
You can check the Django version installed in your project by using this command:
(django-blog) D:\django-blog>django-admin --version 3.2
Creating a new Django project
Let’s create a 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:
Creating a blog application
As the Django project consists of a collection of apps that are created according to their specific functions. We are going to create a ‘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 the 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 we should require in our application.
For simplicity to understand, we put only necessary fields like title, author, slug, body, and published date without which the blog cannot be complete.
If you successfully created this application, then you should definitely make your application more advanced by adding extra fields like status, tags, and others.
Inside the models.py file of the 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
- title: This is the field for the post title and it is limited to a maximum of 250 characters and set to unique so that no two blog posts can have the 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 are also deleted.
- body: This is the field where the author writes his/her content 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 ordering = (‘-publish’). It denotes that whenever we query the Post model it retrieves the posts in descending order. Thus the recent posts appear first in the query result.
- In __str__() method we return the title of the post, to specify the particular post from the number of posts by title in the administration site, query object name, and others.
Applying migrations
We designed a 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 the administration site
We have to add the model to the administration site to appear 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 the blog application and add the following lines of code:
# blog/admin.py from django.contrib import admin from .models import Post admin.site.register(Post)
Creating an administration site
The 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.
Superusers can have the authority of creating, editing, and deleting blog posts i.e. have the overall authority of managing the site like creating a new user and assigning permissions and others.
We can create a superuser by running the command:
(django-blog) D:\django-blog>python manage.py createsuperuser Username (leave blank to use 'pythonsansar'): admin Email address: info@pythonsansar.com Password: ******* Password (again): ****** Superuser created successfully.
Now start running the Django server again with the command python manage.py runserver
and then open the link in your browser:
http://127.0.0.1:8000/admin/
Adding blog posts
Now let’s add two-three blog posts from the admin section so that we have a sample of data to work with:
Working on views
We are going to use class-based views for displaying all posts and specific posts through generic ListView and DetailView offered by Django. This base view allows listing objects of any kind.
Class-based views have more benefits than function-based views as we do not have to write all stuff from scratch. Hence our time will be saved and the code looks more clear by using class-based views.
In the views.py file of the blog application, create the two class-based views BlogListView and BlogDetailView:
# 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 models into the views.py file of the 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, specify the template_name that we are going to use for two class-based views. We will be creating those templates 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 naming the URL project-wide. Thus URL patterns allow mapping 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')), ]
Now, we have done our backend part, now left work is the frontend part that consists of HTML, CSS, and Javascript codes.
Creating templates for views
Let’s create a project-level directory called templates(on a working directory) and inside that directory create one base.html file and another blog directory. Your file structure should look like this:
templates/ base.html blog/ blog_list.html blog_detail.html
Why is base.html needed?
base.html is the file that includes the main HTML structure of the website and divides the content into the main content, header, footer, and sidebar. So that other templates do not need to implement the same header, and footer on each page.
The blog_list.html and blog_detail.html will simply inherit from the base.html following the DRY principle(Do not Repeat Yourself).
Now we have to update the TEMPLATES section of the 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 a frontend CSS framework called Bootstrap that takes care of 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/bootstrap@4.6.0/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/bootstrap@4.6.0/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 the templates section also by adding two HTML files named blog_list.html for displaying all blog posts and another blog_detail.html for displaying a detailed view of blog posts whenever the user of the site clicks the Read more button from the list of posts.
Note: In the above both the templates blog_list.html and blog_detail.html, we have inherited base.html so that we do not have to add a 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:
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 them clearly.
I hope you learn the basic concepts of developing a blog site from this article. If you are 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 a comment system, and sharing systems in near future. The best way to learn any programming language is just by doing real projects.
For reference to this blog project, you can refer to this Github repository!
Happy Learning 🙂
nice post