{% extends "list_view.html" %} {% load i18n %} {% comment %} Overrides the outer `content` block, not page.header/page.content-wrapper. Those two sit inside page_view.html's , a plain block div between and that breaks the flex chain the height depends on — from there the filled layout cannot be built at all (specs/027-table-layout-and-column-styling/research.md R5). This view writes its own markup instead: the container and the two toolbars are bypassed, not reused. All six block names page_view.html declares are re-declared below, in positions that make sense for this layout, so a project overriding any of them on a table view keeps working. page.actions does not use {{ block.super }}, because its default (list_view.html's search/sort/filter/create) includes sort, which a table view's own action set must not (FR-007) — see MVPTableViewMixin.actions. The trail used to be folded into this title bar, with the

as its final crumb, so that a full-screen table did not spend a row restating its own heading. The trail is drawn in the app header now, which buys that row back on every page rather than only this one, so the heading is a plain

again and page.header has nothing of its own left to draw. The block stays declared, because a project may have filled it. Written out here rather than as a component. It is markup for one view, which is the case Article XI exempts, and one caller does not justify the abstraction Article III warns about. If a second view ever wants this bar, it becomes a component then. The bars are plain flex rows rather than , for two reasons. A toolbar sizes each slot to its content, but these bars have to span the table's full width to put the actions and the pagination at the trailing edge. And a toolbar renders {{ actions }} in its trailing slot, where a Cotton slot falls through to the context variable of the same name when the caller fills no slot — so any page whose context carries an `actions` key prints its repr there. Nothing here puts one in context, but a bare row keeps the trap shut whatever a project puts in its own. Padding sits on the bars, never on the page. The table is meant to reach the edges of the space the shell gives it: its scrollbar hugs the shell edge and its rows use the full width. Padding on would inset the scroll region along with everything else. runs at gap="0" for the same reason — a gap is space the bars do not control, and the table should meet them rather than float between them. The bars own their own spacing. app.footer is emptied. The shell's footer belongs to a page that ends; this one does not — the viewport is fully spent on the table, and a footer under it either steals rows or never comes into view. It is blanked here rather than turned off in config, so it stays a per-view decision. {% endcomment %} {% block app.footer %}{% endblock app.footer %} {% block content %} {% block page.content-wrapper %}
{% block page.title %}
{% block page.header %} {% endblock page.header %}

{{ page.title }}

{% if page.subtitle %}

{{ page.subtitle }}

{% endif %}
{% block page.actions %} {% endblock page.actions %}
{% endblock page.title %}
{% block page.content %} {% endblock page.content %}
{% block page.footer %} {% if page_obj %}
{% with start=page_obj.start_index end=page_obj.end_index total=page_obj.paginator.count %} {% blocktrans with name_plural=model_info.verbose_name_plural %} Showing {{ start }}-{{ end }} of {{ total }} {{ name_plural }} {% endblocktrans %} {% endwith %}
{% endif %} {% endblock page.footer %}
{% endblock page.content-wrapper %}
{% endblock content %}