djangodjango-viewsmixins

Django mixins for class-based-generic views


I am trying to implement staff_member_required mixins:

Here are the two ways I found on how to do so:

First:

class StaffRequiredMixin(object):
    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_staff:
            messages.error(
                request,
                'You do not have the permission required to perform the '
                'requested operation.')
            return redirect(settings.LOGIN_URL)
        return super(StaffRequiredMixin, self).dispatch(request,
            *args, **kwargs)

Second:

class StaffRequiredMixin(object):
    @classmethod
    def as_view(self, *args, **kwargs):
        view = super(StaffRequiredMixin, self).as_view(*args, **kwargs)
        return staff_member_required(view)

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_staff:
            messages.error(
                request,
                'You do not have the permission required to perform the '
                'requested operation.')
            return redirect(settings.LOGIN_URL)
        return super(StaffRequiredMixin, self).dispatch(request,
            *args, **kwargs)

What I want to know is:

  1. Why the second way is overriding the as_view() method and wrapping it with staff_member_required ?

  2. Do we get any 'additional' advantages by doing so ?

I am new to these mixins. Please help.


Solution

  • TL; DR: they're close to the same, the difference is in checking is_active as well as is_staff and the error messages. You probably don't need both because the as_view override negates the need for the dispatch override anyway.

    These are really just two ways of doing close to the same thing.

    This code:

    class StaffRequiredMixin(object):
        @classmethod
        def as_view(self, *args, **kwargs):
            view = super(StaffRequiredMixin, self).as_view(*args, **kwargs)
            return staff_member_required(view)
    

    ...could actually be used alone to implement the staff_member_required decorator. In this case the staff_member_required functionality gets called in the view's as_view() function (i.e., from as_view() in your URLConf).

    This code:

    class StaffRequiredMixin(object):
        @method_decorator(login_required)
        def dispatch(self, request, *args, **kwargs):
            if not request.user.is_staff:
                messages.error(
                    request,
                    'You do not have the permission required to perform the '
                    'requested operation.')
                return redirect(settings.LOGIN_URL)
            return super(StaffRequiredMixin, self).dispatch(request,
                *args, **kwargs)
    

    ...filters users in the dispatch method. You can see in the Django codebase that as_view actually calls dispatch. This means that if you use both together you won't actually ever trigger the if not request.user.is_staff code in the dispatch method because any user who doesn't pass would have been filtered out in the as_view method.

    The second difference is that staff_member_required is slightly different from what the first code does. If you check out the code, you'll notice that staff_member_required also checks whether the user's is_active flag passes (not just is_staff like in your dispatch decorator). It also doesn't pass the messages.error like in your code.