• 
      

    Add a new module for dynamic page state injections.

    Review Request #14548 — Created Aug. 4, 2025 and submitted — Latest diff uploaded

    Information

    Djblets
    release-5.x

    Reviewers

    TemplateHook is a powerful way of letting extensions add content to
    templates with minimal effort, but it has two problems:

    1. It's limited to extensions, meaning it's not possible for other code
      to leverage the functionality.

    2. It has no say in the caching information, meaning the final ETag for
      a page may not consider dynamic changes to the content from the
      hooks.

    This change adds a new piece of architecture that makes the benefits of
    TemplateHook and hook points more generally-useful in an application.

    djblets.pagestate allows templates to set up page hook points that
    content can be injected into via a {% page_hook_point %} template tag.
    This is much like {% template_hook_point %} for extensions.

    These interface with a PageState instance, which is bound to an
    HttpRequest. These are created/accessed using
    PageState.for_request(request). A PageState tracks any injected
    content for the page, along with ETags for that content.

    Injections can be manual (through PageState.inject() calls) or dynamic
    (through registered injector objects). The dynamic ones work more like
    TemplateHook.

    Injections can provide content (HTML-safe or unsafe) and ETags, but
    either are optional. If an ETag is not provided, the content will be
    used in its place (in either case, this is seed data for a SHA256 hash
    for the resulting ETag). An injection with just an ETag and no content
    is also allowed, as that can be useful for ensuring state generated
    elsewhere for the page is considered in the resulting ETag.

    PageStateMiddleware manages the resulting ETag for the page. If the
    response does not include an ETag, we leave it alone (so we don't cause
    a page with other dynamic elements to be cached incorrectly). If it does
    include an ETag, it will be mixed with the PageState's ETag into a
    final ETag.

    TemplateHook is now built on all this. The {% template_hook_point %}
    tag simply wraps {% page_hook_point %}, and an injector is registered
    that bridges to the registered TemplateHooks. ExtensionsMiddleware
    also interfaces with PageStateMiddleware if not otherwise defined in
    settings.MIDDLEWARE. This means that no changes are needed for
    projects using extensions today. Everything just works.

    Unit tests pass.

    Tested that existing extensions using TemplateHook continue to work
    correctly.

    Built some new code using this support, and verified it worked as
    expected.

    Built the docs and checked the new guide for any obvious errors.

    Commits

    Files