William Karlsson
William Karlsson

Reputation: 219

Syntax behind how as_view() delivers callable, DJANGO

I will keep this question short. Similar questions on S/O do not address what I am wondering about, and I have struggled to find an answer.

When I point to a CBV in my urls.py, I use the as_view class method:

...MyView.as_view()...

Looking at the actual script (django/django/views/generic/base.py), the as_view returns a function 'view' that is specified within the actual class method itself. How come it returns the function with this line:

return view

Why does it not have to specify:

return view(request, *args, **kwargs)

I tried this out myself. I went and created a FBV_1 that returned yet another FBV_2 (the view responsible for delivering all functionality), in this same manner:

return fbv_2

It generated an error. I had to return fbv_2(request) to access it.

Thank you in advance. Apologies for any idiomatic expression-errors, my Swedish sometimes gets the best of me.

Upvotes: 0

Views: 847

Answers (3)

wobbily_col
wobbily_col

Reputation: 11879

"view" is the function name name.

In this case we have defined the function within another function - as_view(). Think of the name "view" as a variable pointing to code rather than data.

view 

is the function - we have defined it (within the as_view() function). It already knows what arguments to expect from the line:

def view(request, *args, **kwargs):
    ... 
    ..

A function is just code.

To execute the function you would usually type the function name followed by parenthesis enclosing any arguments.

view(request, kwarg1=var1 , kwarg2=var2) 

calls the function called view and executes the code.

I hope that makes sense. Its not difficult, but a bit tricky to describe.

Upvotes: 1

fixmycode
fixmycode

Reputation: 8506

You're missing some important details in your investigation: The as_view() class method never takes hold of the request object or function arguments, it just returns a callable for the function it declares in its definition. Returning a callable is different to returning an object or in this case, a Response object. When an url object is evaluated, your code does something like the following, let's make some URL objects:

url(r'/some_pattern/', views.some_view)
url(r'/other_pattern/', views.ClassBasedView.as_view())

when I go to /some_pattern, some_view is defined as a callable, so it can be executed as a function:

views.some_view(request, *args, **kwargs)

when I go to /other_pattern/, the class-based view is expected to return a callable after as_view(), which it does:

views.ClassBasedView.as_view()(request, *args, **kwargs)

this is evaluated to:

view(request, *args, **kwargs)

which in turn is evaluated to:

self.dispatch(requests, *args, **kwargs)

where self is an instance of ClassBasedView, and dispatch always returns an HttpResponse of some sort:

HttpResponse('hello!')

So! after all this, if you don't see how your premise is faulty, let's complete your test, you have the following:

def fbv_2(request, *args, **kwargs):
    return HttpResponse('hello!')

def fbv_1(request, *args, **kwargs):
    return fbv_2

and the following URL definition:

url(r'/test/', views.fbv_1)

Then, when I point my browser to /test/:

views.fbv_1(request, *args, **kwargs)

which is evaluated to

views.fbv_2

Uhm, so what happened? well, the Handler expected some sort of HttpResponse, but instead received a function pointer, which he wont evaluate. You see, the as_view() method is what we call a Factory, its job is to create view functions based on what the class defines as instance methods, because the Handler can't understand instance methods, just functions.

Upvotes: 1

Basalex
Basalex

Reputation: 1187

All functions in Python are first-class objects. You don`t have to call it before return, you can do whatever operations you like with functions without calling them, you can even set attrs for functions:

func.level = 5

The difference is just when you call function on return, function response would be returned, and when don't the function itself is returned. Basically, is_view method returns the same view function as you would`ve written in your views.py:

def view(request):
     ...
     return HttpResponse(...)

As you can see it always has request as the first param.

Upvotes: 0

Related Questions