Only the Poster Edits
Part of the Class-Based Views section of Coddy's Django journey. Lesson 16 of 18.
Log in as grace and open /jobs/python-developer-brightline/edit/: ada posted that job, and grace can change it. Job pages show Edit only to the poster, but anyone can type the address or send a POST, so the view itself must refuse.
UserPassesTestMixin calls a method you write, test_func(), before the view runs. When it returns True, the request goes through. When it returns False, a logged-in user gets a 403 Forbidden response, for a GET and a POST alike. A recipe site lets nobody change a published recipe:
class RecipeUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Recipe
fields = ["title", "minutes"]
def test_func(self):
return not self.get_object().publishedThe test runs before the view has looked the row up, so self.object does not exist yet. self.get_object() finds the row from the URL, the way the view will.
Challenge
MediumOnly a job's poster may edit or delete it. In jobs/views.py, add UserPassesTestMixin to JobUpdateView and JobDeleteView, after LoginRequiredMixin. The test passes only for the user who posted the job, and anyone else gets 403 Forbidden, on GET and POST.
Log in as grace (coddy-pass-123) and open /jobs/python-developer-brightline/edit/: ada posted it, so you see 403 Forbidden.
Try it yourself
from django.contrib.auth.mixins import LoginRequiredMixin
from django.urls import reverse_lazy
from django.views.generic import CreateView, DeleteView, DetailView, ListView, TemplateView, UpdateView
from .models import Job
class HomeView(TemplateView):
template_name = "jobs/home.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["count"] = Job.objects.count()
context["latest"] = Job.objects.order_by("-posted").first()
return context
class AboutView(TemplateView):
template_name = "jobs/about.html"
class JobListView(ListView):
model = Job
context_object_name = "jobs"
ordering = ["-posted"]
paginate_by = 5
def get_queryset(self):
jobs = super().get_queryset()
city = self.request.GET.get("city")
if city:
jobs = jobs.filter(city=city)
return jobs
class JobDetailView(DetailView):
model = Job
class JobCreateView(LoginRequiredMixin, CreateView):
model = Job
fields = ["title", "company", "city", "salary", "description"]
def form_valid(self, form):
form.instance.posted_by = self.request.user
return super().form_valid(form)
class JobUpdateView(LoginRequiredMixin, UpdateView):
model = Job
fields = ["title", "company", "city", "salary", "description"]
class JobDeleteView(LoginRequiredMixin, DeleteView):
model = Job
success_url = reverse_lazy("jobs:list")
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Class-Based Views
4Editing Views
CreateViewLanding on the New JobPractice on your own: Django playground