Django: why is ViewClass.as_view used with brackets in URLconf?

Viewed 91

If I have a view-class and I want to use it in URLconf, I will have to use its as_view()-method, since the view-class isn't a function, but a class. My question is, in URLconf, why is as_view() called with brackets? Doesn't this mean that the function will be run upon reading URLconf? If so, what is it exactly that as_view does?

Example:

# urls.py
from django.conf.urls import url
from some_app.views import AboutView

urlpatterns = [
    url(r'^about/$', AboutView.as_view()), # <--- We're calling the method. Why?
]
1 Answers

Almost all views that people create in Class Based Views are subclasses of the core Django CBVs. That means that you inherit the as_view method, as you've pointed out above. Why do we need that? It's just below the section in docs that declares the CBV I believe you've taken as an example for your question:

# some_app/views.py
from django.views.generic import TemplateView

class AboutView(TemplateView):
    template_name = "about.html"

So in the urls.py, you could reference this - except the Django urls dispatcher is looking for a callable function (after 1.10).

Because Django’s URL resolver expects to send the request and associated arguments to a callable function, not a class, class-based views have an as_view() class method which returns a function that can be called when a request arrives for a URL matching the associated pattern.

Each subclassed view inherits the as_view method which provides this, being called at URL delcaration time. This returns a function, which can be used at request time (per Daniel's comment below.)

And from the as_view section of the docs:

When the view is called during the request/response cycle, the HttpRequest is assigned to the view’s request attribute. Any positional and/or keyword arguments captured from the URL pattern are assigned to the args and kwargs attributes, respectively. Then dispatch() is called.

This makes it function in the same way as the longer-winded FBV, which takes in a request, does stuff and then returns an HttpResponse:

def some_view(request): 
    pass #do some stuff 
    context = { "foo": "bar"}
    return render(request, 'about.html', context)
Related