How to Build Blog CMS (Content Management System) with Django

How to Build Blog CMS (Content Management System) with Django

Learn how to build Blog CMS (Content Management System) with Django. Django is a Python based web application framework which is helpful for building a variety of web application. Django also includes an extensible Django-Admin interface, Default SQLIte3 database, which is also extensible to PostgreSQL, MySQL databases, and few other components to build efficient web apps.

Django is a Python based web application framework which is helpful for building a variety of web application. Django also includes an extensible Django-Admin interface, Default SQLIte3 database, which is also extensible to PostgreSQL, MySQL databases, and few other components to build efficient web apps.

Install and Setup Django

Create a directory for our blog, install and activate the virtual environment. Then install Django using below commands

## creating directory for our project
mkdir gfgblog && cd gfgblog

## installing virtual environment
pip install virtualenv
python3 -m venv env

## activating virtual environment
source env/bin/activate

## installing django
pip install django

As now we have installed Django we will now create a Django project which will set up a basic Django app

django-admin startproject gfgblog
cd gfgblog

In our gfgblog Django app, we will have these files

  • *init.py * – empty file
  • urls.py – for routing our django project
  • settings.py – has all settings for our django project
  • asgi.py, wsgi – helpful while deploying our app

We are in Django web app directory. Now we will make some migrations for our database which will be an SQLite3 which will setup some default tables to run our app in our database. Then we will create a superuser for our app.

## migrating tables
python3 manage.py makemigrations
python3 manage.py migrate

## create and enter the details for superuser
python3 manage.py createsuperuser

creating, migrating django-app

Now run the django development server and open port 8000 in your localhost

## running python development server
python3 manage.py runserver

default django page

Now stop the server and go into gfgblog directory in our gfgblog django app directory and open urls.py file using your code editor. You can look tree of our gfgblog directory from below picture

django app directory tree structure

Create a Blog App in Django

Now we will create our actual blog app and database for it. Go to the gfgblog project directory. You can see our SQLite3 database, gfgblog django app. now in this directory create a new app named blog. The below command will create a new app for us.

## creating an app named blog
python3 manage.py startapp blog

The new app directory has 5 default files

  • init.py – an empty file
  • admin.py – for managing admin interface
  • apps.py – for managing app configuration
  • models.py – for managing database models of the app
  • tests.py – for testing the app
  • views.py – for managing behaviour and logic of the app

As we have created the app now we have to tell the django app that there is an new app in out project. For that go to settings.py in gfgblog directory and open settings.py file. Go ti installed apps section of the settings file add the name of the app we created in our case its blog

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

Creating Models for Blog CMS

Now we will create Django models for the app.You can learn more about Django Models from this tutorial – Django Models

To create Django Models open in your editor and add the below code

## importing django models and users
from django.db import models
from django.contrib.auth.models import User

STATUS = (
    (0,"Draft"),
    (1,"Publish"),
    (2, "Delete")
)

## creating an django model class
class posts(models.Model):
    ## title field uing charfield constraint with unique constraint
    title = models.CharField(max_length=200, unique=True)
    ## slug field auto populated using title with unique constraint
    slug = models.SlugField(max_length=200, unique=True)
    ## author field populated using users database
    author = models.ForeignKey(User, on_delete= models.CASCADE)
    ## and date time fields automatically populated using system time
    updated_on = models.DateTimeField(auto_now= True)
    created_on = models.DateTimeField()
    ## content field to store our post
    content = models.TextField()
    ## meta descrption for SEO benifits
    metades = models.CharField(max_length=300, default="new post")
    ## status of post
    status = models.IntegerField(choices=STATUS, default=0)

    ## meta for the class
    class Meta:
        ordering = ['-created_on']
    ## used while managing models from terminal
    def __str__(self):
        return self.title

Save the file and make migration so that the fields will be created in our database using the below commands

## creates migrations for the blog app
python3 manage.py makemigrations blog

## migrates the blog app
python3 manage.py migrate blog

So far we are good with creating models and setting our database for storing our posts, but we should present them to users. Luckily django comes with its own templating language with which we can build dynamic HTML pages to serve our users. We can also add styling using CSS and JavaScript. You can learn more about django templates this tutorial – Django Templates

Creating Templates for Blog CMS –

To create templates first create template directory in blog app (You can also create it outside the blog app but in this way it would be easy to manage). To manage templates in an easy way for each app in the project we have to do some change in the settings. Go to the project settings file and replace template settings with the code below

TEMPLATES_DIR = os.path.join(BASE_DIR,'templates')

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [TEMPLATES_DIR],
        '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',
            ],
        },
    },
]

Now we will create templates for our blog. As django can build pages dynamically we will build our templates according to it. Now we will create a base template which servers as a base for all the pages in our blog.

<!DOCTYPE html>
<html lang="en">
<head>
<!-- will be replaced with meta content -->
{% block metatags %}{% endblock %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous">
<style>
html, body {
height: 100%;
}
body {
    font-family: sans-serif;
    font-size: 18px;
    background-color: #fdfdfd;
display: flex;
flex-direction: column;
}
#nofooter {
flex: 1 0 auto;
}
darkbtn {
color: #66ff99; }
.dark-mode {
    background-color: black;
    color: white;
}
#foot {
    flex-shrink: 0;
    font-family: sans-serif;
background-color: #BDFFD3; color: #00308F;
    bottom: 0px;
    width: 100%;
}
.card-group,.card,.card-footer,.card-body {
border: none;
}
</style>
</head>
<body><div id="bodydiv"><div id="nofooter">
<nav class="navbar navbar-expand-lg navbar-light bg-light shadow" id="topnav">
    <div class="container-fluid">
    <a class="navbar-brand" href="{% url 'home' %}">
    <img src="/static/icons/logo.png" width="30" height="30" class="d-inline-block rounded align-top" alt="logo" loading="lazy">
    GeeksForGeeks</a>
    <div class="nav justify-content-end">
        <div class="d-inline"><a class="nav-link text-black font-weight-bold" href="{% url 'posts'%}">Posts</a></div>
        </div></div>
</nav>
<!-- will be replaced with post content -->
{% block content %}
{% endblock content %}
</div>
<footer class="footer" id="foot">
<div class="container"><h5 style="text-align:center;">Enjoy the Blog and Stay Updated</h5>
<nav class="navbar navbar-expand-lg">
<div class="container-fluid">
<p>Copyright © GeeksForGeeks</p>
<div class="nav justify-content-center" id="navfooter">
<span><a class="nav-link text-black font-weight-bold" href="{% url 'about' %}">About</a></span>
<span><a class="nav-link text-black font-weight-bold" href="{% url 'privacy' %}">Privacy</a></span>
<span><a class="nav-link text-black font-weight-bold" href="{% url 'tos' %}">Terms</a></span>
<span><a class="nav-link text-black font-weight-bold" href="http://feeds.feedburner.com/hackingandprogramming-news">Feed</a></span>
</div>
</div>
</nav>
    </div>
</footer></div>
</body>
</html>

This will be our base template, You can blocks like {% block name %}{% endblock %} which will be replaced with the content assigned to them, Now we will create a home template which would be the homepage for our blog which will have the latest posts.

{% extends "base.html" %}
{% block metatags %}
<title>Home | GeeksForGeeks</title>
<meta name="description" content="A destination for Learning">
<meta property="og:title" content="GeeksForGeeks">
<meta property="og:site_name" content="GeeksForGeeks">
<meta property="og:url" content="https://GeeksForGeeks.org">
<meta property="og:description" content="A destination for Learning">
<meta property="og:type" content="website">
{% endblock %}
{% block content %}
<style type="text/css">
    body {
    font-family: 'Raleway', sans-serif;}
    .head_text {
        color: white;
    }
.h1, h4 {
font-family: 'Raleway', sans-serif;
}
#mainhome {
text-align: center; }
</style>
<header class="jumbotron" style="background-color: #BDFFD3; color: #00308F;">
    <div class="container">
    <p class="h1"> Welcome to <strong>GeeksForGeeks</strong></p>
                </div>
</header>
<div class="container">
    <div class="row">
        <div class="col-md-8 mt-3 left">
            {% for post in posts_list %}
            <div class="shadow-none card mb-4" id="newsfeed">
                <div class="card-body">
                    <h3 class="card-title">{{ post.title }}</h3>
                    <p class="card-text text-muted h6"><span>{{ post.author.first_name }} {{ post.author.last_name }}</span> | {{ post.created_on}} </p>
                    <p class="card-text">{{post.metades }}</p>
                    <span><a href="{% url 'post_detail' post.slug %}" class="btn btn-outline-primary">Read More →</a></span><span><a href="{% url 'post_detail_amp' post.slug %}" class="btn btn-outline-success">AMP page</a></span>
                </div>
            </div>
            {% endfor %}
        </div>
</div>
</div>
{% if is_paginated %}
<nav aria-label="Page navigation conatiner"></nav>
<ul class="pagination justify-content-center">
    {% if page_obj.has_previous %}
    <li><a href="?page={{ page_obj.previous_page_number }}" class="btn btn-outline-info" style="font-family: sans-serif;">« PREV </a></li>
    {% endif %}
    {% if page_obj.has_next %}
    <li><a href="?page={{ page_obj.next_page_number }}" class="btn btn-outline-info" style="font-family: sans-serif;"> NEXT »</a></li>

    {% endif %}
</ul>
{% endif %}
{%endblock%}

We have created our homepage with pagination. Posts will be displayed using the for loop. Now we will add our last template to display posts individually.

{% extends 'base.html' %}
{% block metatags %}
<title>{{ object.title }}</title>
<meta name="description" content="{{ object.metades}}" />
<meta property="og:title" content="{{ object.title }}">
<meta property="og:site_name" content="GeeksForGeeks">
<meta property="og:url" content="{% url 'post_detail' object.slug %}">
<meta property="og:description" content="{{ object.metades }}">
<meta property="og:type" content="article">
{% endblock %}
{% block content %}
<style type="text/css">
#container img {
border-radius: 29px;
width: 100%;
height: 360px;
opacity: 0.7;
align-content: center;
}
#container img {
opacity: 1.0; }
a {text-align: center; text-decoration: none;}
</style>
<script type="application/ld+json">
{
"@context": "https://schema.org/",
"@type": "Post",
"headline": "{{ object.title }}",
"description": "{{ object.metades }}",
"mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "{% url 'post_detail' object.slug %}"
},
"author": {
    "@type": "Person",
    "name": "{{ post.author.first_name }} {{ post.author.last_name "
},
"publisher": {
    "@type": "Organization",
    "name": "GeeksForGeeks",
},
"datePublished": "{{ news.created_on }}",
"dateModified": "{{ news.created_on }}",
"mentions": "{{ object.source }}"
}
</script>
<div class="container">
<div class="row">
<div class="col-md-6 left">
        <h1 class="card-title">{% block title %} {{ object.title }} {% endblock title %}</h1>
        <p class=" text-muted">{{ object.author.first_name }} {{ object.author.last_name }} |{{ object.created_on }}</p>
        <p class="card-text">{{ object.content | safe }}</p>
    </div>
    </div>
    </div>
{% endblock content %}

Both homepage and post page will be built by extending base template and replacing blocks with the data stored in our database. Both also has facebook open graph for better sharing and social network and post page has structured schema for better SEO additionally. We will build AMP template in coming tutorial.

Creating Views for Blog CMS –

Now open views.py file in blog directory. This file has the logic to run the blog app. We will be using class-based views for blog app. Class Based Generic Views are advanced set of Built-in views which are used for implementation of selective view strategies such as Create, Retrieve, Update, Delete.

## importing models and libraries
from django.shortcuts import render
from .models import posts
from django.views import generic
from django.views.decorators.http import require_GET
from django.http import HttpResponse

## class based views for posts
class postslist(generic.ListView):
    queryset = posts.objects.filter(status=1).order_by('-created_on')
    template_name = 'home.html'
    paginate_by = 4

## class based view for each post
class postdetail(generic.DetailView):
    model = posts
    template_name = "post.html"

Creating Routes for Blog CMS –

For Routing our blog app just go into the blog app directory and create a file urls.py to route our app. see the code below

## importing django routing libraries
from . import views
from django.urls import path, include
from .views import *
from .feeds import blogFeed

urlpatterns = [
    ## home page
    path('', views.postslist.as_view(), name='posts'),
    ## route for posts
    path('<slug:slug>/', views.postdetail.as_view(), name='post_detail'),
]

Go to urls.py file in gfgblog directory and route our blog app. See the code below for reference

from django.contrib import admin
from django.urls import path, include, re_path
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    ## urls handling admin route
    path('admin/', admin.site.urls),
    ## urls handling blog routes
    path('', include('blog.urls')),
]

Done, Let’s Now run the server using

Python manage.py runserver

Blog CMS Screenshots –

HomePage –

homepage with latest’s posts

*A sample post page – *

sample post page

Posts management with Django Admin

posts management

User management via Django Admin

User management

Originally published at https://www.geeksforgeeks.org/building-blog-cms-content-management-system-with-django/

python django web-development programming developer

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Hire Python Developers

Are you looking for experienced, reliable, and qualified Python developers? If yes, you have reached the right place. At **[HourlyDeveloper.io](https://hourlydeveloper.io/ "HourlyDeveloper.io")**, our full-stack Python development services...

Hire Python Developers India

Looking to build robust, scalable, and dynamic responsive websites and applications in Python? At **[HourlyDeveloper.io](https://hourlydeveloper.io/ "HourlyDeveloper.io")**, we constantly endeavor to give you exactly what you need. If you need to...

Python Django Full Course | Django Tutorial | Django Web Framework

Python Django full course | Django Tutorial | Django Web Framework | you will be learning almost everything you need to create web application with Django framework.

Basic Data Types in Python | Python Web Development For Beginners

In the programming world, Data types play an important role. Each Variable is stored in different data types and responsible for various functions. Python had two different objects, and They are mutable and immutable objects.