Goal for this part
Let signed-in people compose a post, like someone else’s post, and leave a short comment. Authors can edit or delete only their own posts. Likes and comments use HTMX fragments.
Concepts
Ownership is a query: post.author_id == request.user.id. Do not hide the edit button and call that security — hide the button and check in the view. Unique constraints make like-toggle safe under double-clicks: insert or delete, never increment a counter column by hand.
Walkthrough
from django.utils.text import slugify
from django.utils.crypto import get_random_string
def compose(request):
form = PostForm(request.POST or None)
if request.method == "POST" and form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.slug = slugify(post.body[:40]) + "-" + get_random_string(6)
post.save()
return redirect("posts:detail", slug=post.slug)
return render(request, "posts/compose.html", {"form": form})@login_required
@require_POST
def toggle_like(request, slug):
post = get_object_or_404(Post, slug=slug)
like, created = Like.objects.get_or_create(user=request.user, post=post)
if not created:
like.delete()
return render(request, "posts/_like_button.html", {"post": post, "user": request.user})Comments are a small POST on the detail page. Cap them at 280 characters. Strip leading/trailing whitespace and reject empty bodies. Return the new comment list fragment so the form can clear with hx-on::after-request or a swapped empty textarea.
How to run it and what you should see
Sign in as Ada. Compose “Block party on Saturday.” The post should appear on the feed and on Ada’s profile. Like Grace’s post: the heart count increments without reload. Comment on it. Sign in as Grace and confirm she cannot open Ada’s edit URL.
Common mistakes
Slug collisions happen if you only slugify the first words — append a short random suffix. A like view that accepts GET will be triggered by prefetch. Deleting a post must cascade likes and comments (the foreign keys already do if you set on_delete=CASCADE).
Try this
Double-click Like quickly. The count should land on 0 or 1, never 2. Then delete your own post and confirm its detail URL 404s.