The Page Registry¶
About this document
This is the API reference for the resume page extension point: the
ResumePage base class, the PageRegistry, capability-based
section selection, page discovery, and the navigation template tags.
For a task-oriented how-to (defining a page, templates, navigation, shipping
a page as its own package) see Creating Page Plugins. For the
design rationale see Pluggable Resume Pages. The three built-in pages
(CoverLetterPage, CvPage, PermissionDeniedPage) are documented in
The Views.
Overview¶
A page is a registered ResumePage subclass that owns a route under
<slug:slug>/, the section plugins it renders, access control, navigation
metadata, and themed-template selection. Pages mirror content plugins: there is
a PageRegistry and a module-level page_registry singleton,
exactly as The Plugin Registry describes for plugins. Page content keeps living in
the section plugins’ Resume.plugin_data, so adding a page needs no model and
no migration.
ResumePage¶
- class django_resume.pages.ResumePage¶
Base class for a registered resume page. Subclass it, set the class attributes, and override the hooks you need.
- url_name¶
The URL name used for
reverse()(e.g.reverse("django_resume:cv", kwargs={"slug": slug})). It is also the registry key, so it must be unique across registered pages.
- path¶
The sub-segment appended to
<slug:slug>/. Use""for the default/root page; the bare<slug:slug>/catch-all is always emitted last byPageRegistry.get_urls(), so more specific paths never shadow it (and it never shadows them).
- template_name¶
Resolved as
django_resume/pages/{theme}/{template_name}wherethemeisresolve_page_theme()of the resume — the active theme if it ships the template, otherwise theplainfallback.
- section_names¶
Which section plugins the page builds context for. Accepts an explicit list of plugin names (
["identity", "about"]), the string"__all__"(every registered section plugin), or aByCapabilityselector fromby_capability(). It is an inclusion filter, not an ordering — the template decides layout by including sections by name.
Human-friendly label for navigation menus. The empty default means the page is reachable by URL but not advertised in navigation.
Integer navigation order; lower sorts first. The sort is stable, so pages sharing a value keep registration order. Default
0. The built-ins use 10 (Cover), 20 (CV), 30 (the 403 editor).
Navigation group label. Links sharing a
nav_grouprender together underpage_nav_groups(). The empty default keeps the page in the implicit ungrouped bucket.
- check_access(request, resume)¶
Return
Noneto proceed, or anHttpResponseto short-circuit (e.g. a 403 or a login redirect). Default:None.
- is_visible(resume)¶
Whether the page is advertised in navigation for
resume. Override for state-dependent links (the built-in 403 editor returnsresume.token_is_required). Default:True.
The page’s URL for
resume, reversed via thedjango_resumeapplication namespace.
- get_context(request, resume, *, base_context)¶
Build the template context. The default resolves the theme (with
plainfallback) and callsbuild_section_context()forsection_names, so the section fragments render through the same theme the page frame resolves to.
- serve(request, resume, base_context)¶
Build the page response. The default renders
template_namefor the resolved theme with the context fromget_context(). Override to take full control of rendering (for example to return anHttpResponsewithout a themed template).
- finalize_response(response, request, resume)¶
Post-process every response the dispatcher returns — including a short-circuit response from
check_access()— e.g. to set headers. Default: returnsresponseunchanged.
Selecting sections by capability¶
- django_resume.pages.by_capability(*capabilities, match='any')¶
Build a
ByCapabilityselector forResumePage.section_names. Withmatch="any"(the default) a plugin is included if it carries at least one ofcapabilities; withmatch="all"it must carry every one. An empty capability set matches nothing. Any othermatchvalue raisesValueError.section_names = by_capability("portfolio") section_names = by_capability("portfolio", "cv", match="all")
Section plugins advertise their tags through
Plugin.capabilities(atuple[str, ...], empty by default). Access/UI-control plugins such astokenandthemecarry no capabilities and are never selected as content.
- class django_resume.pages.ByCapability¶
The selector returned by
by_capability(); a frozen dataclass withcapabilitiesandmatchfields and amatches(plugin)predicate. Prefer theby_capability()factory at call sites.
PageRegistry¶
- class django_resume.pages.PageRegistry¶
A registry of resume page classes, instantiated once as the
page_registrysingleton.- register(page_class)¶
Instantiate
page_classand store it under itsurl_name. Re-registering the sameurl_namereplaces the entry.
- register_page_list(page_classes)¶
Call
register()for each class inpage_classes.
- unregister(page_class)¶
Remove the page registered under
page_class.url_name(a no-op if absent).
- get_page(url_name)¶
Return the registered page instance for
url_name, orNone.
- get_all_pages()¶
Return all registered page instances in registration order.
- get_ordered_pages()¶
Return all registered pages sorted by
nav_order. The sort is stable, so equal orders keep registration order — navigation is deterministic for built-ins plus any third-party pages.
- get_urls()¶
Return the generated
URLPatternlist, one<slug:slug>/{path}per page, with the bare<slug:slug>/(path == "") catch-all emitted last by construction.django_resume.urlssplices this into itsurlpatterns.
- django_resume.pages.page_registry¶
The module-level singleton instance of
PageRegistry, shared across the application.
Discovery¶
Built-in pages are registered in AppConfig.ready before plugin
registration. Third-party pages are then discovered two ways, both before
django_resume.urls is imported (which evaluates
PageRegistry.get_urls() once), so every page has a route before the
URLconf freezes.
- django_resume.pages.autodiscover_pages()¶
Import each installed app’s top-level
resume_pagesmodule (mirroring Django admin’sautodiscover_modules) so apps register pages by import side-effect, then callload_entry_point_pages().
- django_resume.pages.load_entry_point_pages()¶
Register pages contributed by separately distributed packages that are not installed Django apps, through
ENTRY_POINT_GROUPentry points. Each entry point loads to either aResumePagesubclass (registered directly) or a zero-argument callable (invoked so it can register its own pages); any other target raisesTypeError. Loading is idempotent.
- django_resume.pages.ENTRY_POINT_GROUP¶
The entry-point group name,
"django_resume.pages". A distribution declares an entry point in this group:[project.entry-points."django_resume.pages"] contact = "mypkg.pages:ContactPage"