Why the attributes of a object in __init__() and get_context_data() different?

Viewed 80
class SomeView(DetailView) :
    def __init__(self, *kwargs):
        print(type(self), dir(self)) 
    def get_context_data:
        print(type(self), dir(self)) 

__ init__ does not prints "request attribute" for dir(self), but get_context_data() prints.

Why such a difference?

1 Answers

The request is not set by the __init__ of the view. Indeed, it is set by the setup function:

    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        self.request = request
        self.args = args
        self.kwargs = kwargs

This setup is done after the View object is constructed. Indeed, if you use .as_view() it returns a function that basically is the view function:

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)

It thus first constructs a self (with self = cls(**initkwargs)), and then will call self.setup(request, *args, **kwargs) to set the request object together with the args and kwargs.

If you need to do something after the request is set, you can thus override the setup method. For example:

class SomeView(DetailView):

    def setup(self, *args, **kwargs):
        super().setup(*args, **kwargs)
        print(dir)
Related