0

I'm trying to decorate the login_required Django decorator. I've been looking at this question decorating decorators: try to get my head around understanding it. However, this case is a bit different because I don't want to modify the login_required decorator rather add further functionality to it.

To be clear, I'm trying to create a decorator that decorates a view function (which first argument is request as normal) and that checks for a user parameter. If possible I don't want to create my own version of the decorator as proposed here Django: Tweaking @login_required decorator because I think this is a security critical method that might be modified in the future.

This is what I've got so far but it isn't working.

from django.conf import settings
from django.contrib.auth.decorators import login_required, REDIRECT_FIELD_NAME
from django.http.response import HttpResponseRedirect
from django.utils.decorators import available_attrs
from functools import wraps


def login_and_def_pass_required(view_function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
    def decorate_view(view_function):
        @wraps(view_function, assigned=available_attrs(view_function))
        def _double_wrapped_view(request, *args, **kwargs):
            actual_decorator = login_required(view_function, redirect_field_name, login_url)
            if request.user.temporary_password:
                return HttpResponseRedirect(settings.SET_PERMANENT_PASSWORD_URL)
            return actual_decorator
        return _double_wrapped_view
    return decorate_view

This raises the exception "'function' object has no attribute 'get'".

I'm using Django 1.8.4 Python 3.4

Community
  • 1
  • 1
zom-pro
  • 1,571
  • 2
  • 16
  • 32
  • 1
    Any reason you can't use [`user_passes_test`](https://docs.djangoproject.com/en/1.8/topics/auth/default/#django.contrib.auth.decorators.user_passes_test) decorator *on view*? – J0HN Aug 24 '15 at 16:35
  • How would you use it in combination with login required? – zom-pro Aug 24 '15 at 16:37
  • 1
    @login_required()\n@user_passes_test(login_url=SET_PERMANENT_PASSWORD_URL)\ndef view(request, ...). Comments on SO removes newlines, so I've added them as \n – J0HN Aug 24 '15 at 16:38
  • took me while to test it. That's it though. If you put it as an answer I could accept it (as the right answer). Not the most popular question sadly... – zom-pro Aug 25 '15 at 10:27
  • Glad it helped. Posted an answer. – J0HN Aug 25 '15 at 12:43

1 Answers1

2

You can use user_passes_test cooperatively with login_required to achieve the desired behavior:

def check_permanent_password(user):
    return not user.temporary_password

@login_required(login_url)
@user_passes_test(check_temporary_password, login_url=settings.SET_PERMANENT_PASSWORD_URL)
def view(request):
    # your view
J0HN
  • 26,063
  • 5
  • 54
  • 85