1

I have lots of class-based views in my app. Most of them should be accessible only by authentificated staff users. How can I easylly add user check for lot of class-based views?

For standart function views I added decorator like this:

def only_staff_allowed(fn):
    '''decorator'''
    def wrapped(request, *args, **kwargs):
        if request.user.is_staff:
            return fn(request, *args, **kwargs)
        else:
            return HttpResponseRedirect(reverse('moderator:login'))
    return wrapped

@only_staff_allowed
def dashboard(request):
    ''' now accessible only by staff users '''
    return render(request, 'moderator/dashboard.html', {})

How can I do somthing similar to class-based views like this?

class AddressesAddList(ListView):
    template_name = 'moderator/addresses/add_list.html'
    queryset = Address.objects.filter(need_moderating=True)
    paginate_by = 100

Should I add some mixins or override some methods? Or can I decorate something?

3 Answers 3

6

Actually, there are at least three ways to avoid decorating the dispatch method of each and every view class you want to require login for.

If you only have a few such views, you can either use that decorator in the URLconf, like this:

url(r"^protected/$", login_required(ProtectedView.as_view()), name="protected_view"),

Alternatively, and better if you have a bit more views to protect, is to use the LoginRequiredMixin from django-braces:

from braces.views import LoginRequiredMixin

class ProtectedView(LoginRequiredMixin, TemplateView):
    template_name = 'secret.html'

And, if you have a lot of views to protect, you should use a middleware to cover a bunch of views in one fell swoop; something along the lines of:

class RequireLoginMiddleware(object):
    """Requires login for URLs defined in REQUIRED_URLS setting."""
    def __init__(self):
        self.urls = tuple([re.compile(url) for url in REQUIRED_URLS])
        self.require_login_path = getattr(settings, 'LOGIN_URL', '/accounts/login/')
    def process_request(self, request):
        if not request.user.is_authenticated() and request.path != self.require_login_path:
            for url in self.urls:
                if url.match(request.path):
                    return HttpResponseRedirect(u"{0}?next={1}".format(self.require_login_path, request.path))
Sign up to request clarification or add additional context in comments.

Comments

4

You should decorate the dispatch method of the class-based view. See below.

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super(ProtectedView, self).dispatch(*args, **kwargs)

See the docs here.

Comments

1

You can use LoginRequiredMixin. This will redirect unauthenticated users to the page set.

from braces.views import LoginRequiredMixin

class DashboardIndex(LoginRequiredMixin, TemplateView):
    template_name = 'dashboard/index.html'
    login_url = 'action:login' #Where you must set the page else will use default.
    raise_exception = False

https://django-braces.readthedocs.org/en/latest/access.html#loginrequiredmixin

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.