Posts CRUD

View saved

Goal for this part

Let authors manage their own posts from the public site. You will add detail, create, update, and delete views—typically Django class-based views—with login and ownership checks.

After this snapshot, Campus Press supports a full create/read/update/delete loop for blog posts without using the admin for everyday writing.

What you should already know

You should understand the Post model, authentication, and login_required / mixins. Reading class-based view docs helps, but the snapshot keeps each class small and focused.

Ownership matters: only the author should update or delete a post. Mixing in user checks prevents one account from editing another’s work.

Concepts: CreateView, UpdateView, DeleteView

Class-based views supply a pattern for forms tied to models. You set model, fields, and success_url (or get_absolute_url on the model). LoginRequiredMixin and UserPassesTestMixin guard write operations.

On create, set form.instance.author = self.request.user in form_valid so the foreign key is always the logged-in user.

from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.views.generic import CreateView, UpdateView, DeleteView

class PostCreateView(LoginRequiredMixin, CreateView):
    model = Post
    fields = ["title", "content"]

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Post
    fields = ["title", "content"]

    def test_func(self):
        return self.get_object().author == self.request.user

Walkthrough: detail links and get_absolute_url

Add get_absolute_url on Post so create/update can redirect to the detail page. Link titles on home to that detail route. DeleteView should confirm before destroying a row.

Wire URL patterns with <int:pk> converters for detail, update, and delete.

from django.urls import reverse

class Post(models.Model):
    # ... fields ...
    def get_absolute_url(self):
        return reverse("post-detail", kwargs={"pk": self.pk})

How to run it and what you should see

Run 09-Posts-CRUD, log in, create a post, edit it, open its detail page, then delete it. Try editing someone else’s post while logged in as a second user—you should be denied.

git clone https://github.com/michaeldunga1/fcc-django-blog.git
cd fcc-django-blog/09-Posts-CRUD
python3 -m venv .venv
source .venv/bin/activate
pip install -r ../requirements.txt
python manage.py migrate
python manage.py runserver

Common mistakes and troubleshooting

If author is null on create, you forgot to set it in form_valid. If update allows any user, test_func is missing or always returns True. TemplateDoesNotExist for post_form.html means the expected CBV template name is not in the snapshot path Django searches.

Try this

Create two users and two posts. Confirm each user only sees edit/delete controls for their own posts if the templates gate those links on user == post.author.

  • CBVs reduce boilerplate for standard model forms
  • Always set author from request.user
  • Ownership checks belong in the view, not only in the template

Next: Pagination

Comments

One comment per signed-in account. Comments are saved with this page’s URL.