Django staff login to all urls
Question:
I want to define some specific urls starts with /staff/* to access only by staff. So only staffs can access the urls starts with /staff/*
How can I define that in Django ?
Answers:
Use a custom middleware. If the url starts with /staff/ and request.user is not staff, raise Http404 or return some special message to client.
Below is an example:
For django version < 1.10:
class StaffCheckMiddleware(object):
def process_request(self, request):
full_path = request.get_full_path()
if full_path.startswith('/staff/') and not request.user.is_staff:
raise Http404
For django version 1.10 or above:
class StaffCheckMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
full_path = request.get_full_path()
if full_path.startswith('/staff/') and not request.user.is_staff:
raise Http404
response = self.get_response(request)
return response
Then add StaffCheckMiddleware
in settings.py
.
You can use user_passes_test
or staff_member_required
decorator for the view that you associate with your url (that starts with /staff/
), an example might be as follows:
With user_passes_test
decorator:
from django.contrib.auth.decorators import user_passes_test
@user_passes_test(lambda u: u.is_staff, login_url='/some_url/')
def your_view(request, ...):
# Only for staff
With staff_member_required
decorator:
from django.contrib.admin.views.decorators import staff_member_required
@staff_member_required
def your_view(request, ...):
# Only for staff
For class-based views I just took the LoginRequiredMixin in django source code and created a new mixin using this base:
website/utils/is_staff_mixin.py
from django.contrib.auth.mixins import AccessMixin
from django.utils.translation import gettext_lazy as _
from django.contrib import messages
from django.shortcuts import redirect
class IsStaffMixin(AccessMixin):
"""Verify that the current user has staff status."""
def handle_no_permission(self, request):
messages.add_message(request, messages.ERROR, _("You need higher permissions in order to access this page."))
return redirect("index")
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
messages.add_message(request, messages.ERROR, _("You need to be logged in in order to access this page."))
return redirect("login")
if not request.user.is_staff:
return self.handle_no_permission(request)
return super().dispatch(request, *args, **kwargs)
If the user is not logged in, I redirect to the login page. If the user is logged in but don’t have the is_staff
var set to True
, I redirect to my homepage.
Here’s a real world example:
website/apps/gallery/views.py
from website.utils.is_staff_mixin import IsStaffMixin
from django.views.generic import DetailView, ListView
from .models import Gallery
class ListGalleriesView(IsStaffMixin, ListView):
model = Gallery
paginate_by = 5
context_object_name = "galleries"
queryset = Gallery.objects.all().order_by("-date_added")
class GalleryView(IsStaffMixin, DetailView):
model = Gallery
context_object_name = "gallery"
I want to define some specific urls starts with /staff/* to access only by staff. So only staffs can access the urls starts with /staff/*
How can I define that in Django ?
Use a custom middleware. If the url starts with /staff/ and request.user is not staff, raise Http404 or return some special message to client.
Below is an example:
For django version < 1.10:
class StaffCheckMiddleware(object):
def process_request(self, request):
full_path = request.get_full_path()
if full_path.startswith('/staff/') and not request.user.is_staff:
raise Http404
For django version 1.10 or above:
class StaffCheckMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
full_path = request.get_full_path()
if full_path.startswith('/staff/') and not request.user.is_staff:
raise Http404
response = self.get_response(request)
return response
Then add StaffCheckMiddleware
in settings.py
.
You can use user_passes_test
or staff_member_required
decorator for the view that you associate with your url (that starts with /staff/
), an example might be as follows:
With user_passes_test
decorator:
from django.contrib.auth.decorators import user_passes_test
@user_passes_test(lambda u: u.is_staff, login_url='/some_url/')
def your_view(request, ...):
# Only for staff
With staff_member_required
decorator:
from django.contrib.admin.views.decorators import staff_member_required
@staff_member_required
def your_view(request, ...):
# Only for staff
For class-based views I just took the LoginRequiredMixin in django source code and created a new mixin using this base:
website/utils/is_staff_mixin.py
from django.contrib.auth.mixins import AccessMixin
from django.utils.translation import gettext_lazy as _
from django.contrib import messages
from django.shortcuts import redirect
class IsStaffMixin(AccessMixin):
"""Verify that the current user has staff status."""
def handle_no_permission(self, request):
messages.add_message(request, messages.ERROR, _("You need higher permissions in order to access this page."))
return redirect("index")
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
messages.add_message(request, messages.ERROR, _("You need to be logged in in order to access this page."))
return redirect("login")
if not request.user.is_staff:
return self.handle_no_permission(request)
return super().dispatch(request, *args, **kwargs)
If the user is not logged in, I redirect to the login page. If the user is logged in but don’t have the is_staff
var set to True
, I redirect to my homepage.
Here’s a real world example:
website/apps/gallery/views.py
from website.utils.is_staff_mixin import IsStaffMixin
from django.views.generic import DetailView, ListView
from .models import Gallery
class ListGalleriesView(IsStaffMixin, ListView):
model = Gallery
paginate_by = 5
context_object_name = "galleries"
queryset = Gallery.objects.all().order_by("-date_added")
class GalleryView(IsStaffMixin, DetailView):
model = Gallery
context_object_name = "gallery"