Chapter 12 of 12
Build a full blog with CRUD โ create, read, update, and delete posts. Users can register, log in, write posts, and edit their own content. This is a complete, deployable Django application.
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="posts")
body = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ["-created_at"]
def __str__(self):
return self.title
def get_absolute_url(self):
from django.urls import reverse
return reverse("post-detail", kwargs={"slug": self.slug})from django.contrib.auth.decorators import login_required
from django.shortcuts import render, redirect, get_object_or_404
from django.utils.text import slugify
from .models import Post
from .forms import PostForm
def post_list(request):
posts = Post.objects.filter(published=True)
return render(request, "blog/list.html", {"posts": posts})
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug, published=True)
return render(request, "blog/detail.html", {"post": post})
@login_required
def post_create(request):
form = PostForm(request.POST or None)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.slug = slugify(post.title)
post.save()
return redirect(post.get_absolute_url())
return render(request, "blog/form.html", {"form": form, "action": "Create"})
@login_required
def post_edit(request, slug):
post = get_object_or_404(Post, slug=slug, author=request.user)
form = PostForm(request.POST or None, instance=post)
if form.is_valid():
form.save()
return redirect(post.get_absolute_url())
return render(request, "blog/form.html", {"form": form, "action": "Edit"})
@login_required
def post_delete(request, slug):
post = get_object_or_404(Post, slug=slug, author=request.user)
if request.method == "POST":
post.delete()
return redirect("post-list")
return render(request, "blog/confirm_delete.html", {"post": post})