Introduction to Class-Based Views
Class-based views (CBVs) in this codebase provide a structured and reusable alternative to function-based views. By leveraging inheritance and mixins, they allow developers to encapsulate common view logic—such as template rendering, context management, and HTTP method dispatching—into discrete, manageable components.
The Foundation: The View Class
The View class in django/views/generic/base.py is the parent for all class-based views. It is designed to be simple, implementing only dispatch-by-method and basic sanity checking.
The Entry Point: as_view()
The as_view() class method is the primary entry point for a request-response process. It returns a function that can be used in a URLconf. When called, it instantiates the class and triggers the view's lifecycle.
# Example from tests/generic_views/urls.py
path(
"template/simple/<foo>/",
TemplateView.as_view(template_name="generic_views/about.html"),
),
Initialization and Setup
When a request arrives, the view instance undergoes initialization via the setup() method. This method assigns the request, args, and kwargs to the instance, making them available to all other methods.
Critical Requirement: If you override setup(), you must call super().setup() to ensure the request attribute is correctly attached. Failure to do so results in an AttributeError.
# django/views/generic/base.py
def setup(self, request, *args, **kwargs):
"""Initialize attributes shared by all view methods."""
if hasattr(self, "get") and not hasattr(self, "head"):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
The Dispatch Mechanism
The dispatch() method determines which HTTP handler (e.g., get(), post()) should process the request based on the request.method.
- It converts the request method to lowercase.
- It checks if the method is in the allowed
http_method_nameslist. - It retrieves the corresponding method from the class (defaulting to
http_method_not_allowed).
Managing Context with ContextMixin
The ContextMixin provides a standardized way to pass data to templates. Its primary method, get_context_data(), returns a dictionary that serves as the template context.
By default, it includes the view instance itself in the context and merges any data defined in the extra_context attribute.
# django/views/generic/base.py
class ContextMixin:
extra_context = None
def get_context_data(self, **kwargs):
kwargs.setdefault("view", self)
if self.extra_context is not None:
kwargs.update(self.extra_context)
return kwargs
In practice, subclasses often override this to inject specific data:
# Example from tests/generic_views/views.py
class CustomTemplateView(generic.TemplateView):
template_name = "generic_views/about.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context.update({"key": "value"})
return context
Template Rendering with TemplateResponseMixin
The TemplateResponseMixin encapsulates the logic for selecting a template and rendering it into an HttpResponse.
template_name: A string specifying the template to use.get_template_names(): Returns a list of template names. It must be overridden iftemplate_nameis not provided.render_to_response(): Uses theresponse_class(defaulting toTemplateResponse) to render the provided context.
Concrete View Implementations
TemplateView
TemplateView is a concrete implementation that combines View, ContextMixin, and TemplateResponseMixin. It is used to render a template for GET requests.
# django/views/generic/base.py
class TemplateView(TemplateResponseMixin, ContextMixin, View):
def get(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
return self.render_to_response(context)
RedirectView
RedirectView provides a flexible way to handle redirects. It supports both hardcoded URLs and named URL patterns.
url: The specific URL to redirect to.pattern_name: The name of a URL pattern to reverse.permanent: Determines if the redirect is a 301 (Permanent) or 302 (Found).query_string: IfTrue, the original query string is appended to the redirect URL.
The logic for determining the destination is contained in get_redirect_url():
# django/views/generic/base.py
def get_redirect_url(self, *args, **kwargs):
if self.url:
url = self.url % kwargs
elif self.pattern_name:
url = reverse(self.pattern_name, args=args, kwargs=kwargs)
else:
return None
# ... query string logic ...
return url
Async Support in Views
The View class includes a view_is_async class property that inspects the HTTP handlers (like get or post). This codebase enforces consistency: all handlers in a single view class must be either synchronous or asynchronous. Mixing sync and async handlers in the same class will raise an ImproperlyConfigured error.
When a view is async, the as_view() method ensures the returned callback is marked as a coroutine function using markcoroutinefunction.