23👍
The underlying implementation of these views involves some fairly advanced Python, so if you’re a relative beginner it’s not surprising if you find some of this code confusing.
-
The main thing you should understand is what the
@classmethod
decorator does on the definition ofas_view()
. This means that this method is not a normal method, which is called on an instance of the class (and takes the instance as theself
parameter), but a classmethod, which is called on the class itself (and takes the class as thecls
parameter). Some languages refer to that as a static method, although in Python that’s a third type of method that we don’t need to go into here. -
This is because of how the view is defined in the urlconf. You correctly put
WelcomeView.as_view()
– what this does is call theas_view
classmethod at the time that the urlconf is imported. -
As we know from point 1,
cls
is the view class itself. As normal with a class, when you call it, you get an object. So, as you say, what we’re doing here is instantiating the class, then assigning that instance to a variable calledself
, as if we were inside a method of that instance. The point here is that as I said above,as_view
is called at import time, and it returns a function –view
– that is in turn called by the URL dispatcher when a browser requests that URL. So inside that function, we construct and call the rest of the class that makes up the class-based view. As to why it’s needed, see below. -
The
__init__
method takes care of setting each member ofinitargs
to an instance attribute, where you can access it in your view code via the usualself.whatever
syntax.
So, why is all this necessary?
Class-based views come with a huge potential gotcha, which is that any class instantiated directly in the URLconf (or anywhere else at module level) will persist throughout the entire lifetime of the process. And the way that Django is commonly deployed – via WSGI – usually means that one process can last for many many requests. And if you have something persisting across multiple requests, you have the potential for some really nasty thread-safety bugs – if you set something to an instance attribute in one request, for example, it will be visible in subsequent requests.
So, this code not only ensures that each request gets a new instance, it also makes it really hard to break that request isolation by dynamically constructing the instance each time inside the view function.
2👍
1.
Firstly as_view() is a class method. This is a method that can be called on a class rather than an instance of a class. And in this case you can see it’s being call on View
, which is a class rather than an instance.
2.
as_view()
is called when the url.conf module is loaded – it returns the function view()
. It’s this function that’s called every time a view is requested – as_view
doesn’t need to be called again.
3.
In the scope of the view()
function, the cls
variable is the View
class (eg DetailView
, ListView
, or whatever child of View
is calling the function). Refering to the first argument of a class method as cls
is a coding style specification from PEP8. It’s similar to the way we refer to the first argument of am instance method as self. So
self = cls(**initkwargs)
is basically the same as
self = View(**initkwargs)
or self = DetailView(**initkwargs)
(depending on which class is inheriting this function).
This is, as you say, instantiating a new instance of the class. Up to this point, a View
object has yet to be instantiated.
4.
Lastly the initkwargs are used when an instance of the class is created. It’s really as simple as adding each key, value pair as attributes of the new view object –
for key, value in kwargs.iteritems():
setattr(self, key, value)
- Catch exception on save in Django admin?
- What is the main difference between clean and full_clean function in Django?