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.