Multiple admin sites, restrict access per user or group

English is not my native language, i hope to be able to explain my problem adequately anyways! If not, please ask and let me try again!

I have very unequal user know-how levels and created multiple admin sites for the different levels. My custom user model has an “is_expert” boolean for the users between “is_staff” and “is_superuser”.

Some of the users use my easyadminsite via URL /easyadmin/, others use the expertadminsite via /expertadmin/

This works but some of the non-experts THINK they are experts and use the /expertadmin/ and mess things up.

How do i restrict users without the “is_expert” flag to use the whole expertadminsite but still allow access to the easyadminsite? They all work on the same models / instances so the standard permissions don’t help. Of course i could override the four has_xxx_permissions in all modeladmin classes but it would be better to restrict access to the whole site all together.

Create a custom middleware that will redirect the user to a specific URL. You can use this documentation to guide you.
Here’s a snippet that i used when i implemented this exact feature.

from typing import Union
from django.http import HttpRequest
from django.shortcuts import redirect
from rest_framework.request import Request as RestHttpRequest

from users.models import User
from utils.consts.users import UserType


class AdminRedirectMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request: Union[HttpRequest, RestHttpRequest]):
        path = request.get_full_path()
        if self.is_authenticated_admin_get_request(request):
            admin_url_for_user_type = self.get_url_for_user_type(request.user)
            if admin_url_for_user_type == path:
                return self.get_response(request)
            if admin_url_for_user_type not in path:
                return redirect(admin_url_for_user_type)
        return self.get_response(request)

    @staticmethod
    def is_authenticated_admin_get_request(request):
        path = request.get_full_path()
        return (
            request.method == "GET"
            and "admin/" in path
            and "static/" not in path
            and "jsi18n/" not in path
            and request.user.is_authenticated
        )

    def get_url_for_user_type(self, user: User):
        urls = {
            UserType.CUSTOMER: "/",
            UserType.ADMIN: "/la-admin/",
            UserType.COMPANY: "/cmp-admin/",
            UserType.FRANCHISEE: "/frn-admin/",
        }
        return urls[user.user_type]

You can handle it on the site level.

See AdminSite.has_permission

You can create your ExpertAdminSite with a custom has_permission function that checks the is_expert flag.

1 Like

Didn’t know about that!
That solution is way cleaner.

I feel so stupid right now! It is that simple and i did not find it in weeks? Ouch!

Thank you for the Hint!