In Django, how do you serve a mostly static About page with TemplateView, and how do you add data to its template context?
answer
- no views.py needed at all
- template_name as an as_view() keyword
- a dict merged into context
- super() first, then add keys
basics
~10 sRoute to TemplateView.as_view(template_name="about.html"); it renders that template on GET. Add fixed values with extra_context, or subclass and override get_context_data(), calling super() first so URL kwargs, view and extra_context stay in the context.
solid answer
~30 s`TemplateView` renders `template_name` for GET (and HEAD) requests, so a static page needs no view code: `path("about/", TemplateView.as_view(template_name="about.html"))`. Its context comes from `ContextMixin.get_context_data()`: the keyword arguments captured from the URL pattern, a `view` entry pointing at the view instance, and then `extra_context`, a dict you can set as a class attribute or pass to `as_view()`. For data that must be computed per request, subclass and override `get_context_data(**kwargs)`: call `super().get_context_data(**kwargs)` first, add keys to the returned dict and return it. If you forget `template_name` and do not override `get_template_names()`, the view raises `ImproperlyConfigured` on the first request.
code
python · 9 linesfrom django.test import TestCase
class AboutPageTests(TestCase):
def test_about_page_uses_template_and_context(self):
response = self.client.get("/about/ethics/")
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, "pages/ethics.html")
self.assertEqual(response.context["section"], "about")go deeper
Recall that TemplateView.as_view(template_name=...) serves a static page and that extra_context or get_context_data() adds template variables.
Explain the context build order: URL kwargs, then view, then extra_context, then whatever your override adds after super().
Separate constants from per-request data: extra_context is evaluated once per process, so anything dynamic belongs in get_context_data().
Decide when a URLconf-only TemplateView is clearer than a named subclass, weighing discoverability and testability across a large project.
## What TemplateView is for A news site has pages that are almost pure template: About, Contact, Editorial Standards. Writing a function that only calls `render()` for each one is boilerplate. Django's **`TemplateView`** (in `django.views.generic`) is a ready-made class-based view that renders one template on `GET`, and on `HEAD` through the base `View` alias. Its class hierarchy explains everything it does: - **`TemplateResponseMixin`** supplies `template_name`, `get_template_names()` and `render_to_response()`. - **`ContextMixin`** supplies `extra_context` and `get_context_data()`. - **`View`** supplies `as_view()`, `setup()` and `dispatch()`. `TemplateView.get()` is two lines: build the context with `get_context_data(**kwargs)`, then return `render_to_response(context)`. ## Zero-code usage in the URLconf ```python from django.urls import path from django.views.generic import TemplateView urlpatterns = [ path("about/", TemplateView.as_view(template_name="pages/about.html"), name="about"), path( "about/ethics/", TemplateView.as_view( template_name="pages/ethics.html", extra_context={"section": "about"}, ), ), ] ``` Both `template_name` and `extra_context` are existing attributes on the class, so `as_view()` accepts them as keyword overrides. Without a `template_name` (and without an overridden `get_template_names()`), the first request raises **`ImproperlyConfigured`** saying the mixin requires either `template_name` or an implementation of `get_template_names()`. ## What ends up in the context `ContextMixin.get_context_data(**kwargs)` builds the dict in this order: 1. Start from the **keyword arguments captured by the URL pattern** — `TemplateView.get()` passes them straight through, so `path("about/<slug:section>/", ...)` makes `{{ section }}` available. 2. `setdefault("view", self)` — the **view instance** is available as `{{ view }}`, so the template can call view methods or read attributes. 3. `update(extra_context)` — **`extra_context`** is merged last, so a key there overrides a URL kwarg of the same name. Context processors, such as the one that adds `request`, run later when the template is rendered; they are not part of this dict. | Source | Set where | Evaluated when | |---|---|---| | URL kwargs | The `path()` pattern | Every request | | `view` | Automatically | Every request | | `extra_context` | Class attribute or `as_view()` keyword | Once, when the class or URLconf is loaded | | Keys added in `get_context_data()` | Your subclass | Every request | The last column is the practical difference: `extra_context` is for **constants**, `get_context_data()` is for anything computed. ## Overriding get_context_data correctly ```python from django.views.generic import TemplateView class AboutView(TemplateView): template_name = "pages/about.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["show_staff_links"] = self.request.user.is_staff return context ``` - **Call `super()` first.** It returns the dict with URL kwargs, `view` and `extra_context`; building a fresh dict throws those away, and with mixins in the chain it also drops whatever they contribute. - **Accept and forward `**kwargs`.** Other callers, including subclasses, pass extra keys through them. - **Return the dict.** Forgetting `return` hands `None` to `render_to_response()`, and the page renders with an empty context: every variable silently comes out blank. ## Using the view from the template Because the context always contains `view`, a template can read attributes and call zero-argument methods on the view instance. That is a tidy way to expose small computed values without widening the context: - `{{ view.template_name }}` shows which template is rendering, handy in a debug footer. - A method such as `def page_title(self): return "About the newsroom"` becomes `{{ view.page_title }}`; the template engine calls callables that take no arguments. - The method runs at render time, per request, so it can read `self.request` safely. Keep this for presentation helpers. Heavy work hidden in a template-called method is hard to find when a page gets slow. ## Choosing the lightest tool | Need | Use | |---|---| | A fixed page with no data | `TemplateView.as_view(template_name=...)` in the URLconf | | A fixed page plus a few constants | The same, with `extra_context={...}` | | Values computed per request | A `TemplateView` subclass overriding `get_context_data()` | | One model object or a list of them | The display generics, not `TemplateView` | ## What TemplateView does not do - It answers `GET` and `HEAD`; a `POST` to it gets **405 Method Not Allowed** because it defines no `post()`. - It does not fetch a model object or list; that is what the display generics are for. - It returns a `TemplateResponse`, which is rendered lazily after the view returns, so middleware and tests can still inspect `response.context_data` and `response.template_name` before rendering.
- A URL kwarg and an extra_context key have the same name. Which value does the template see?The `extra_context` value. `ContextMixin.get_context_data()` starts from the URL kwargs, adds `view` with `setdefault`, then calls `update(self.extra_context)`, so the later update wins. A subclass that sets the key after calling `super().get_context_data()` would override both.
- When is it worth subclassing TemplateView instead of passing everything to as_view()?When the context needs per-request work, such as reading `self.request.user` or querying the database, or when the same page is mounted at several URLs and you want one named class to test. `extra_context` is evaluated once when the URLconf loads, so anything that changes over time belongs in an overridden `get_context_data()`.
saying these in an interview costs you the question
- Writing a function view that only calls render() for every static page
- Overriding get_context_data() without calling super() and returning a fresh dict
- Passing the template name positionally to as_view()
- Believing TemplateView also handles POST submissions
- Putting per-request data such as database queries into extra_context