skip to content

In Django, what do ListView and DetailView need for a property index and property page, and which template and context names do they default to?

level: juniorimportance: must knowfreq 68%

answer

  1. one attribute is often enough
  2. app label, model name, suffix
  3. generic name plus model name
  4. the URL must capture an identifier

basics

~10 s

Set model = Property. ListView renders listings/property_list.html with object_list and property_list; DetailView needs a pk or slug from the URL and renders listings/property_detail.html with object and property.

solid answer

~30 s

Both views only need `model = Property` (or a `queryset`). `ListView` fetches every row through the model's default manager and renders `<app_label>/<model_name>_list.html`, so `listings/property_list.html` for a `Property` model in the `listings` app, with the rows in the context as both `object_list` and `property_list`. `DetailView` needs the URL pattern to capture `pk` or `slug`; it loads one object, returns 404 if there is none, and renders `listings/property_detail.html` with the object as both `object` and `property`. The model part is `_meta.model_name`, the lowercased class name. `template_name` and `context_object_name` override the defaults when the names do not suit the project.

code

html · 8 lines
html
{# listings/property_list.html #}
<ul>
  {% for property in property_list %}
    <li><a href="{% url 'property-detail' property.pk %}">{{ property.title }}</a></li>
  {% empty %}
    <li>No homes match right now.</li>
  {% endfor %}
</ul>

go deeper

for a junior

Recall model = ..., the <app>/<model>_list.html and _detail.html template names, and the object_list/object context names plus their model-named aliases.

for a middle

Explain where the names come from (_meta.app_label, _meta.model_name, template_name_suffix) and the ListView fallback asymmetry when template_name is set.

for a senior

Choose explicit template_name and context_object_name when defaults would mislead readers, and know which misconfigurations raise AttributeError or ImproperlyConfigured.

for a principal

Set conventions for when generic defaults are acceptable in a large codebase versus explicit names that survive model renames.

## What the display generics are Django ships two **display generics** in `django.views.generic`: - **`ListView`** shows a collection of objects, such as the index of homes for sale on a real-estate site. - **`DetailView`** shows one object, such as a single property page. Both are class-based views assembled from mixins: `MultipleObjectMixin` or `SingleObjectMixin` fetch the data, a template-response mixin picks the template, and `View` provides `as_view()` and dispatch. For the common case, one attribute configures them. ## The minimal setup ```python from django.urls import path from django.views.generic import DetailView, ListView from listings.models import Property class PropertyListView(ListView): model = Property class PropertyDetailView(DetailView): model = Property urlpatterns = [ path("homes/", PropertyListView.as_view(), name="property-list"), path("homes/<int:pk>/", PropertyDetailView.as_view(), name="property-detail"), ] ``` - `model = Property` means "use `Property._default_manager.all()`", which is `Property.objects.all()` for a model with the usual manager. - The detail pattern **must** capture `pk` or `slug`; those are the default URL keyword names `DetailView` looks for. ## Default template names Both views derive a template path from the model's `_meta`: the **app label**, the **model name** (the class name lowercased) and a **suffix**. | View | Suffix | Template for `Property` in app `listings` | |---|---|---| | `ListView` | `_list` | `listings/property_list.html` | | `DetailView` | `_detail` | `listings/property_detail.html` | Setting `template_name` overrides this. There is one asymmetry: 1. `ListView` puts your `template_name` first but **still appends** the derived name as a fallback, as long as the object list is a QuerySet. 2. `DetailView` uses the derived name only when `template_name` is **not** set. It can also read a template path from a field on the object via `template_name_field`. Where the engines look for these files is a separate topic; the view only produces the list of candidate names. ## Default context names | View | Generic name | Model-derived name | Override | |---|---|---|---| | `ListView` | `object_list` | `property_list` | `context_object_name = "homes"` | | `DetailView` | `object` | `property` | `context_object_name = "home"` | The generic name is always present, so a shared template fragment can use `object` or `object_list`. The model-derived name makes page templates readable. When the list is not a QuerySet (a plain Python list returned by `get_queryset()`), `ListView` cannot derive a model name, so only `object_list` is set, and you must provide `template_name` or the view raises `ImproperlyConfigured`. A `ListView` context also carries the pagination keys `paginator`, `page_obj` and `is_paginated`; they are `None`/`False` unless pagination is switched on. ## Adding to the defaults without losing them Most real pages need one or two extra template variables. Extend the context rather than replacing it: ```python class PropertyDetailView(DetailView): model = Property def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["viewing_slots"] = self.object.viewing_slots.filter(open=True) return context ``` - **Call `super()` first**: it inserts `object` and `property`, then merges the view entry and anything a mixin adds. - **Read `self.object`**, which `get()` has already loaded, rather than looking the object up again. - **Change the suffix, not the whole name**, when several views share a model: `template_name_suffix = "_print"` makes a `DetailView` look for `listings/property_print.html`. ## What happens on a request 1. **`ListView.get()`** sets `self.object_list = self.get_queryset()`, builds the context and renders. An empty list renders normally unless `allow_empty = False`, which turns it into a 404. 2. **`DetailView.get()`** sets `self.object = self.get_object()`, which filters `get_queryset()` by the captured `pk` or `slug` and calls `.get()`. No match raises `Http404`. ## Common mistakes - Naming the template after the class (`listings/Property_list.html`) or forgetting the app directory: the derived path is lowercase and app-scoped. - Capturing `<int:id>` in the URL: `DetailView` looks for `pk` by default, so it fails with an `AttributeError` until you rename the kwarg or set `pk_url_kwarg = "id"`. - Expecting the context to expose a variable named after the view class; the names come from the model.

  • You set template_name on a ListView and the file is missing. Why does Django render listings/property_list.html instead of raising an error?
    `ListView`'s `get_template_names()` returns your `template_name` first and then appends the derived `<app>/<model>_list.html` whenever the object list is a QuerySet. The loader tries the names in order, so a missing custom template silently falls back to the default one if it exists. `DetailView` does not append the fallback when `template_name` is set.
  • When would you set context_object_name on a DetailView?
    When the model-derived name is awkward or collides with something else in the context. For example, a model called `Property` gives the context variable `property`, which reads like Python's built-in of the same name and says little about the page. `context_object_name = "home"` adds `home` alongside the always-present `object`.

saying these in an interview costs you the question

  • Expecting the template to be named after the view class
  • Believing DetailView reads an id kwarg from the URL by default
  • Thinking object_list disappears once context_object_name is set
  • Assuming the model part of the template name keeps its capital letters
  • Believing an empty ListView returns 404 by default