1

I doing some refactoring in our code. A @render_to_json decorator was internally calling an is_logged_in method. I'm removing that in favor of simply adding another explicit @login_required decorator.

Problem is that some of our methods are called via AJAX and are expecting a json response of {"status": "logged_out"} which they then act on. So I need to change our login_required method to somehow check one of two things.

  • Was this method called via AJAX, perhaps detecting the XMLHttpRequest header
  • Was the render_to_json decorator also called for this request. The thought would be that if the login_required method knew that the request was expecting json then it could return the json packet, else redirect as normal.

UPDATE Adding a 3rd option.

  • In every case a method with the @render_to_json decorator, the @login_required decorator is referenced before it. The @login_required method returns HttpResponseRedirect if the user is logged out. In the @render_to_json method how would I check the return type of the login_required method and respond appropriately?

Thoughts? Problems?

I should add I'm also fairly new to Python so I might be missing something basic. If so, help me learn?

UPDATE

I'm going to go ahead and add the two decorators here for reference.

def render_to_json(fn):

    @wraps(fn)
    def inner(request, *args, **kwargs):
        result = fn(request, *args, **kwargs)
        return HttpResponse(json.dumps(result), mimetype='application/json')

    return inner

def login_required(func):
    @wraps(func)
    def _decorator(request, *args, **kwargs):
        if not is_logged_in(request):
            from apps.core.extendedLogging import ExtendedLogging
            ExtendedLogging.log("In login req'd: it appears that the user is not logged in", request)
            request.session['login_referrer_uri'] = request.build_absolute_uri()
            return HttpResponseRedirect(settings.LOGIN_URL)
        return func(request, *args, **kwargs)
    return _decorator
commadelimited
  • 5,656
  • 6
  • 41
  • 77
  • 1
    A decorator has access to all of the arguments that the function it is decorating is called with, so I'm not sure I understand the first bullet point. – David Robinson Jan 31 '13 at 15:45
  • David. Remember that I'm new to Python in general. I suspected that would be the case but wasn't sure. According to this post I would use request.META to gain access to all of the request headers? http://stackoverflow.com/questions/3889769/get-all-request-headers-in-django – commadelimited Jan 31 '13 at 15:53
  • I would specifically be looking for this request header `X-Requested-With XMLHttpRequest` – commadelimited Jan 31 '13 at 15:56

1 Answers1

1

Decorators can access all the data the "Decoratee" is receiving:

def method_decorator(operation):
    """
    On this case operation = view_method
    """
    def wrapper(*args, **kwargs):
        """
        Receives all arguments the requested operation would receive
        """
            request = args[0]
            param = args[1]
            more_param = args[2]

            return operation(request, param, more_param)
    return wrapper

@method_decorator
def view_method(request, param, more_param):
    #something

so, when you are calling "view_method", first you will go throw the "method_decorator" which will then call the "view_method".

Now, in the decorator you can verify whatever you need and pass that new information, for example:

def wrapper(*args, **kwargs):
        ...
        if some_condition:
            request.new_content = new_content
        return operation(request, param, more_param)
return wrapper

This will allow you to receive the new_content on the requested view_method:

@method_decorator
def view_method(request, param, more_param):
    new_content = request.new_content

And, hopefully, the view_method now knows what to do.

You can also bubble up the data from decorator to decorator with this same method.

Damium
  • 64
  • 5