Django Blogging Application: Complete Guide with Code & TinyMCE Integration

By Nischal Lamichhane

5 reads 1 comments 2 likes

Django Blogging Application: Complete Guide with Code & TinyMCE Integration

Published on March 9, 2025


Introduction

This tutorial will guide you through building a full-featured Django Blogging Application from scratch. The blog will include post creation, editing, deletion, TinyMCE integration for rich text, user authentication, and a beautiful Bootstrap-based frontend.

Project Setup

mkdir django_blog
cd django_blog
python -m venv venv
source venv/bin/activate  # On Windows use `venv\Scripts\activate`
pip install django

Now, create a new Django project:

django-admin startproject blog_project .

Creating the Blog App

Run the following command to create a Django app:

python manage.py startapp blog

Installing Required Packages

pip install django-tinymce

Add blog and tinymce to INSTALLED_APPS in settings.py:

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

Configure URLs (urls.py in blog_project)


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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('tinymce/', include('tinymce.urls')),  # TinyMCE URLs
    path('', include('blog.urls')),  # Include blog app URLs
]

Defining the Blog Post Model

In models.py of the blog app:

from django.db import models
from django.contrib.auth.models import User
from tinymce.models import HTMLField

class Post(models.Model):
    title = models.CharField(max_length=255)
    content = HTMLField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True) def __str__(self): return self.title

Registering the Model in Admin

In admin.py:

from django.contrib import admin
from .models import Post
admin.site.register(Post)

Creating Blog Views

In views.py:

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from .models import Post
from .forms import PostForm

def post_list(request):
    posts = Post.objects.all().order_by('-created_at')
    return render(request, 'blog/post_list.html', {'posts': posts})

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

@login_required
def post_create(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_form.html', {'form': form})

@login_required
def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            form.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_form.html', {'form': form})

@login_required
def post_delete(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        post.delete()
        return redirect('post_list')
    return render(request, 'blog/post_confirm_delete.html', {'post': post})

Creating Forms

In forms.py:

from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ['title', 'content']

Setting Up URLs

In urls.py of the blog app:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
    path('post/new/', views.post_create, name='post_create'),
    path('post/edit/<int:pk>/', views.post_edit, name='post_edit'),
    path('post/delete/<int:pk>/', views.post_delete, name='post_delete'),
]

Creating HTML Templates

Create a templates/blog/ directory and add the following files:

base.html


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Blog</title>
</head>
<body>
    <h1><a href="/">My Blog</a></h1>
    {% block content %}{% endblock %}
</body>
</html>

post_list.html


{{% extends "blog/base.html" %}

{% block content %}
    <h2>Blog Posts</h2>
    <a href="{% url 'post_create' %}">New Post</a>
    {% for post in posts %}
        <div>
            <h3><a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a></h3>
            <p>By {{ post.author }} on {{ post.created_at }}</p>
        </div>
    {% endfor %}
{% endblock %}

post_detail.html


{% extends "blog/base.html" %}

{% block content %}
    <h2>{{ post.title }}</h2>
    <p>By {{ post.author }} on {{ post.created_at }}</p>
    <div>{{ post.content|safe }}</div>
    <a href="{% url 'post_edit' post.pk %}">Edit</a>
    <form method="POST" action="{% url 'post_delete' post.pk %}">
        {% csrf_token %}
        <button type="submit">Delete</button>
    </form>
{% endblock %}

post_form.html


{% extends "blog/base.html" %}

{% block content %}
    <h2>Create/Edit Post</h2>
    <form method="POST">
        {% csrf_token %}
        {{ form.media }}
        {{ form.as_p }}
        <button type="submit">Save</button>
    </form>
{% endblock %}

Configuring Static Files and TinyMCE

Configure templates & Add the TinyMCE config in settings.py:

TINYMCE_DEFAULT_CONFIG = {
    'height': 360,
    'width': '100%',
    'plugins': 'advlist autolink lists link image charmap print preview anchor',
    'toolbar': 'undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | outdent indent | link image',
}

LOGIN_URL = '/admin/login/'
LOGOUT_URL = '/admin/logout/'

Running Migrations

python manage.py makemigrations
python manage.py migrate

Creating a Superuser

python manage.py createsuperuser

Running the Server

python manage.py runserver

Conclusion

Congratulations! You have built a Django Blogging Application with TinyMCE integration, authentication, and CRUD functionality. You can now expand it by adding features like categories, comments, and user profiles.

Comments

You must be logged in to post a comment.


Admin

3 weeks, 1 day ago

Here is the link to the repository with Source Code: https://github.com/django-tutorial-dev/blogging-app.git

Also Read

Mastering Python Command-Line Arguments: A Comprehensive Guide
Mastering Python Command-Line Arguments: A Comprehensive Guide

Learn how to use Python command-line arguments effectively to automate tasks, streamline workflows,…

Create the viral Ghibli Art for FREE
Create the viral Ghibli Art for FREE

How to create your own Ghibli Art for Free!

Integrate HTMX with Django: A Modern Alternative to ReactJS
Integrate HTMX with Django: A Modern Alternative to ReactJS

Discover how to integrate HTMX with Django to build modern, interactive web applications. Learn to …

Deploying Django Apps for Free on PythonAnywhere: Step-by-Step Guide
Deploying Django Apps for Free on PythonAnywhere: Step-by-Step Guide

Learn how to deploy Django apps for free on PythonAnywhere with this step-by-step guide. From proje…

Flask Vs Django
Flask Vs Django

This article provides a comprehensive comparison between Flask and Django, two prominent Python web…

Python Heap - Complete Guide to Heap Data Structures in Python
Python Heap - Complete Guide to Heap Data Structures in Python

Learn everything about Python Heap, including heap data structures, the heapq module, min-heaps, ma…