views:

62

answers:

1

In chapter 8 of the Django book there is an example showing a fundamental view wrap method, which receives another view method passed in from any single arbitrary URLconf:

def requires_login(view):
    def new_view(request, *args, **kwargs):
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/accounts/login/')
        return view(request, *args, **kwargs)
    return new_view

I follow most of the logic here, but what I'm not understanding is how the nested new_view definition is receiving the request, *args and **kwargs as it's not being explicitly passed into the requires_login definition.

How exactly is the new_view definition receiving these arguments?

+2  A: 

How new_view works

Let's first look at the new_view function:

def new_view(request, *args, **kwargs):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/accounts/login/')
    return view(request, *args, **kwargs)

When new_view is called, it checks whether the user is authenticated. If the user is authenticated, then new_view calls view and passes it all of the arguments (request, positional arguments, and keyword arguments).

Defining new_view

new_view is not automatically executed. We are using def to define the function, but we are not executing it right away. Instead, we return new_view as a function. Imagine the following code:

def my_view(request):
    # ... some view stuff happens here

my_new_view = requires_login(my_view)

Now, my_new_view is a function. I can call it just like any other function. At no point so far has this new function actually been called.

When my_new_view is called, it receives all its arguments. It then calls my_view, passing all the arguments (request, positional arguments, and keyword arguments) to my_view instead.

(All of this assumes that the user is authenticated, of course. Otherwise, when you call my_new_view, you would get an HttpResponseRedirect, and my_view would never be called.)

view as an argument

requires_login receives a function called view as its argument. view refers to a function, but we're not executing that function yet. view is executed only when new_view is executed.

Wesley
Bingo, that's the one. How did I not see this...? Haha. Make perfect sense now. Thanks!
bobthabuilda
Glad it makes sense. If you haven't looked into Python decorators yet, now would be a great time. Decorators are just functions that accept a function as an argument and return a function, just like `requires_login` here.
Wesley