+263773057669 info@clouditate.com

Django blog

Django is a python web framework that encourages clean and pragmatic design. It uses the MVT design pattern. And we’re going to create a Django blog today.

We’re going to create a blog using the Django web framework. Many people love Django and python but don’t have a clue where to start. So I wrote this blog post to get you started both on using a framework and also on blogging. So without wasting much time, let’s dive right in.

Lets first configure our virtual environment so that we don’t corrupt our global environment. If you’re using Linux distro. Here are the commands to install all the python packages needed.

Create blog using Django

sudo apt update && sudo apt upgrade
sudo apt install python3-pip
pip3 install pipenv

Now let’s create the virtual environment itself in a project <myblog> directory and install Django in that environment.

mkdir myblog && cd myblog
pipenv install django==3.0.2
pipenv shell

That’s it. Congratulations, you’ve just created your first virtual environment and installed Django. Now let’s start the Django project in the VIRTUAL ENV we created. Your command must look like:

(myblog) $

Here are the commands to create the actual Django project

(myblog) $ django-admin startproject blog .
(myblog) $ python manage.py migrate
(myblog) $ python manage.py runserver

Every Django project is divided into apps, which are small and pluggable parts of the whole project. Let’s start an app

(myblog) $ python manage.py startapp posts

The app will take care of everything on the blog posts.

Now we’re good to go. So our project is divided into parts. We have the models (database), views, templates, and URLs


A model is a definitive source of data. It stores all data that shapes the behavior of the object you’re defining. You can define database models in python, access that data using a Django API and also using SQL if necessary.

Our blog will have a model for the blog post. So let’s define it inside our posts/models.py.

from django.db import models
from django.utils.translation import gettext_lazy as _
from django.contrib.auth.models import User

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(_("Post title"), max_length=50)
    image = models.ImageField(_("Featured image"), upload_to="posts/")
    exercept = models.TextField(_("Blog summary"))
    body = models.TextField(_("Blog post body"))

    class Meta:
        verbose_name = _("Post")
        verbose_name_plural = _("Posts")

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("post", kwargs={"pk": self.pk})

After creating your data models you have to migrate your data models into the database. Use the following commands

(myblog) $ python manage.py makemigrations
(myblog) $ python manage.py migrate


A view is a “type” of web page in your Django application that serves a specific function and has a template. In our blog, we’ll have a homepage view, about view and contact us view. Let’s define the views in our posts/views.py.

from django.views.generic.list import ListView
from django.views.generic import TemplateView
from .models import Post
# Create your views here.

class Home(ListView):
    template_name = "posts/pages/index.html"
    context_object_name = "posts"
    model = Post

class About(TemplateView):
    template_name = "posts/pages/about.html"

class Contact(TemplateView):
    template_name = "posts/pages/contact.html"


Now, let’s define our template inside the posts application. Create a folder templates/posts/pages and inside pages create the following templates.

  • Index.html
  • post.html
  • about.html
  • contact.html
  • base.html

We are going to use a bootstrap template in our Django app so that we don’t waste time writing HTML and CSS


A base is an abstract layout that all your Django templates will inherit from.

<!doctype html>
<html lang="en">
    <!-- 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://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
   <link rel="stylesheet" href="{% static 'posts/blog.css' %}" >
    <title>{% block title %}Tech Blog{% endblock title %}</title>
        <div class="collapse bg-dark" id="navbarHeader">
            <div class="container">
            <div class="row">
                <div class="col-sm-8 col-md-7 py-4">
                <h4 class="text-white">About</h4>
                <p class="text-muted">Add some information about the blog below, the author, or any other background context. Make it a few sentences long so folks can pick up some informative tidbits. Then, link them off to some social networking sites or contact information.</p>
                <div class="col-sm-4 offset-md-1 py-4">
                <h4 class="text-white">Contact</h4>
                <ul class="list-unstyled">
                    <li><a href="#" class="text-white">Follow on Twitter</a></li>
                    <li><a href="#" class="text-white">Like on Facebook</a></li>
                    <li><a href="#" class="text-white">Email me</a></li>
        <div class="navbar navbar-dark bg-dark shadow-sm">
            <div class="container d-flex justify-content-between">
            <a href="#" class="navbar-brand d-flex align-items-center">
                <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true" class="mr-2" viewBox="0 0 24 24" focusable="false"><path d="M23 19a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h4l2-3h6l2 3h4a2 2 0 0 1 2 2z"/><circle cx="12" cy="13" r="4"/></svg>
            <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarHeader" aria-controls="navbarHeader" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>

    <main role="main">

        {% block content %}
        {% endblock content %}


    <footer class="text-muted">
    <div class="container">
        <p class="float-right">
        <a href="#">Back to top</a>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>


{% extends 'posts/pages/base.html' %}
{% load static %}
{% block content %}
<section class="jumbotron text-center">
    <div class="container">
    <h1>Blog example</h1>
    <p class="lead text-muted">Something short and leading about the collection below—its contents, the creator, etc. Make it short and sweet, but not too short so folks don’t simply skip over it entirely.</p>
        <a href="#" class="btn btn-primary my-2">Main call to action</a>
        <a href="#" class="btn btn-secondary my-2">Secondary action</a>
<div class="album py-5 bg-light">
    <div class="container">
        <div class="row">         
            {% for post in posts %}
            <div class="col-md-4">
                <div class="card mb-4 shadow-sm">
                    <img src="{{post.image.url}}">
                    <div class="card-body">
                        <p class="card-text">{{post.exercept}}</p>
                        <div class="d-flex justify-content-between align-items-center">
                            <div class="btn-group">
                                <a href="{% url 'post' post.pk %}">
                                    <button type="button" class="btn btn-sm btn-outline-secondary">Read More</button>
                            <small class="text-muted">9 mins</small>
            {% endfor %}
{% endblock content %}


{% extends 'posts/pages/base.html' %}
{% load static %}
{% block title %}
{% endblock title %}
{% block content %}
<div class="container">
    <div class="row">         
        <div class="col-md-12">
            <h1 class="text-center">{{post.title}}</h1><br>
            <img src="{{post.image.url}}"/><br>
        {% endfor %}

{% endblock content %}


Create posts/urls.py file and paste the following code

from django.contrib import admin
from django.urls import path
from .views import Home, PostView, About, Contact

urlpatterns = [
    path('', Home.as_view(), name="index"),
    path('about/', About.as_view(), name="about"),
    path('contact/', Contact.as_view(), name="contact"),
    path('post/<int:pk>', PostView.as_view(), name="post"),

Our Models, Views, Templates are ready for the blog. Let’s add some settings in our blog/settings.py


STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATIC_URL = '/static/'
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Extra lookup directories for collectstatic to find static files
    os.path.join(BASE_DIR, 'static'),

Edit your blog/urls.py file

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('posts.urls')),

Your blog is ready for blogging. Create a superuser first. Follow the prompt and put your relevant info

(myblog) $ python manage.py createsuperuser
(myblog) $ python manage.py runserver

Navigate to your page and see if you can add a post.

You can’t right, we left the last part. Register your blog posts in the posts/admin.py

from django.contrib import admin
from .models import Post

Now everything is ready. Happy blogging


Clouditate Services