Menu
CoddyTech

LoginRequiredMixin

Part of the Class-Based Views section of Coddy's Django journey. Lesson 14 of 18.

Right now anyone can post, edit or delete a job without an account. A class has no single function to put @login_required on, so Django gives you a mixin: a small class you add to a view's parents for one extra behaviour.

from django.contrib.auth.mixins import LoginRequiredMixin


class RecipeCreateView(LoginRequiredMixin, CreateView):
    model = Recipe
    fields = ["title", "minutes"]

A logged-out visitor is now sent to /accounts/login/?next=/recipes/new/ before the view runs, on GET and POST alike. After logging in, next brings them back.

The mixin goes first. Every view starts in a method called dispatch(), and Python looks for it in the parents from left to right. Written (CreateView, LoginRequiredMixin), the view's own dispatch() wins, the login check never runs, and nothing warns you.

challenge icon

Challenge

Medium

Only logged-in users may post, edit or delete jobs:

  • Add LoginRequiredMixin to JobCreateView, JobUpdateView and JobDeleteView.
  • The jobs list and the job pages stay open to everyone.

Press Run and press Post a job: you land on the login page. Log in as ada, password coddy-pass-123.

Try it yourself

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(CreateView):
    model = Job
    fields = ["title", "company", "city", "salary", "description"]


class JobUpdateView(UpdateView):
    model = Job
    fields = ["title", "company", "city", "salary", "description"]


class JobDeleteView(DeleteView):
    model = Job
    success_url = reverse_lazy("jobs:list")

All lessons in Class-Based Views

Practice on your own: Django playground