Page Discovery¶
This page covers how the framework discovers pages from the filesystem, registers them, evaluates context, and composes the final body with the ancestor layout chain.
Overview¶
Discovery runs once at startup and again whenever the autoreload watcher fires.
The result is a set of Django URL patterns plus the context callables and layout chains attached to each page.py.
Pipeline¶
flowchart LR
Walk[Filesystem walk] --> Dispatcher[FilesystemTreeDispatcher]
Dispatcher --> Pairs["(url_path, page.py) pairs"]
Pairs --> Manager[Page]
Manager --> ContextReg[Context registry]
Manager --> RenderReq[Render request]
ContextReg --> RenderReq
RenderReq --> Loaders[Template loaders]
Loaders --> LayoutCompose[Layout composition]
LayoutCompose --> InheritedCtx[Inherited page.py context]
InheritedCtx --> PageCtx[Page @context functions]
PageCtx --> Processors[Context processors]
Processors --> Output[Final HTML body]
Modules¶
next.pages.loaders.Registers template loaders such as
DjxTemplateLoader. Each loader recognises one extension and produces a body string for a given page directory.next.pages.manager.Defines the
Pagecoordinator that loads templates, collects context, composes layouts, renders, and builds the pageURLPattern. The process-wide singleton is exposed asnext.pages.pageand the class asnext.pages.Page. The module also implements the@contextdecorator.next.pages.registry.Stores
PageContextEntryrecords and resolves context for a request.next.pages.context.Defines the
Contextmarker and the context-injection providers.next.pages.processors.Discovers and imports the context processor callables listed in each page backend’s
OPTIONS.context_processorsand in the first DjangoTEMPLATESentry. Processors are applied after all@contextfunctions finish, so a processor that returns the same key as a context function overrides it.next.pages.watch.Returns the watch specs that the autoreloader uses to track page directories.
Render Path¶
The view loads the page module through the mtime-keyed module memo, reading from disk only when the file changed.
The body source produces the page body string.
The framework composes the ancestor layout chain, the innermost layout wrapping the page body first and each outer layout wrapping the result. Each layout substitutes the wrapped content into
{% block template %}{% endblock template %}.Page.build_render_contextassembles the template scope, see Context Resolution below.The composed template string renders against the assembled scope.
The static manager replaces the
{% collect_styles %}and{% collect_scripts %}placeholder tokens with the rendered tags accumulated by the request-scopedStaticCollector.
When the body source is a render function that returns an HttpResponseBase, the response is returned verbatim and steps 3 through 6 do not run.
Composed-Template Cache¶
Page keeps two parallel dicts that short-circuit the layout composition step when nothing on disk has changed.
_template_registry.Maps a
page.pypath to its already-composed template string._template_source_mtimes.Snapshots the modification time of every file that contributed to the composition, including the page body source and each ancestor
layout.djx.
On every request _is_template_stale compares the current mtimes against the snapshot.
A change to any contributing file evicts the entry, the composition step rebuilds the template string, and the new snapshot is stored.
The dynamic render path bypasses this cache entirely, so a render function that returns a fresh body never poisons the registry.
Layout Composition¶
The framework reads each ancestor layout.djx from disk and replaces its {% block template %}{% endblock template %} region with the wrapped content.
The innermost layout wraps the page body, the outermost layout wraps everything.
Composition is string substitution, not Django template inheritance, so no page needs an explicit {% extends %}.
The user-facing rules for layout discovery, the placeholder contract, and layout-level context live in Layouts.
Body Source Priority¶
Page._resolve_page_body and _load_static_body in next.pages.manager pick the highest priority body source.
See Pages for the full priority order and the next.W043 conflict warning.
Context Resolution¶
Page.build_render_context assembles the template scope in this order.
URL kwargs from the matched route are seeded into the context dict.
PageContextRegistry.collect_contextruns in two sub-steps.Inherited context. Every
@context(..., inherit_context=True)callable registered in ancestorpage.pyfiles, walked from the current page upward toward the page root.Page-level context. The
@contextcallables declared in the currentpage.py, evaluated after inherited values are in place so the page can shadow any inherited key.
Context processors merge
OPTIONS.context_processorsfrom each page backend entry withcontext_processorsfrom the firstTEMPLATESentry. The page backend paths are concatenated ahead of the Django paths. Deduplication by dotted path keeps the first occurrence, so a path shared by both sources runs once with the page backend taking precedence. Each surviving processor returns a dict that updates the merged scope, so a later processor overrides an earlier key on a collision.Component-level context functions run on demand as each
{% component %}tag is evaluated during rendering.
The dependency resolver shares a per-request cache across all four steps so a value resolved once (for example, the current user from Depends) is not recomputed.
The canonical description is in Context. This page focuses on which module performs each step.
Extension Points¶
Register a new template loader in
NEXT_FRAMEWORK["TEMPLATE_LOADERS"].Subclass
Pageto add metadata for rendering tools.Add a context processor for global template variables.
See Also¶
See also
Pages for the topic guide. Layouts for layout composition. Request Lifecycle for the surrounding request pipeline.