Datasette templates can await plugin functions during rendering
Datasette 0.32 enables Jinja async rendering. Plugin functions can fetch data asynchronously while templates retain ordinary function-call syntax.
A template function that needs database results cannot always return its answer immediately. In an asynchronous application, that work may produce an awaitable value. A synchronous renderer cannot simply treat the pending operation as the completed result. Datasette 0.32, released on 14 November, enables Jinja async mode so plugin-provided functions can perform asynchronous work during template rendering.
The change is small in the application code and broader in what a plugin can express. Datasette's release announcement points to datasette-template-sql, a new plugin allowing templates to execute SQL and render the results. The relevant general capability is that a function called by a template can wait for data through the asynchronous rendering path. A plugin no longer has to complete every such operation before template evaluation begins.
I like SQLite publishing tools that allow modest customizations without requiring a separate web application. A page may need an additional summary query alongside the standard table display. Supporting that through the existing template and plugin mechanisms keeps a useful customization close to the database it describes.
Two changes connect the rendering path
The 0.32 application source creates its Jinja environment with enable_async=True. The environment still enables automatic escaping and retains the template loaders for local overrides, plugin templates and the built-in defaults. Async mode changes how those templates execute, rather than replacing the customization hierarchy.
The base view implementation completes the change by awaiting template.render_async. That is the point at which the request's rendering work enters the asynchronous template API. Merely defining an async Python function would not provide the same integration if the application continued using a synchronous rendering path.
The surrounding code is instructive as well. Before rendering, the view gathers values from the extra_template_vars hook. It already recognizes a callable result and awaits a coroutine returned by that stage. The new capability concerns functions invoked later, from inside the template. These are different moments at which a plugin can require asynchronous work.
That distinction affects how a plugin is structured. Precomputed context values are appropriate when the view always needs the data. A callable supplied to the template allows the template to request a result where its own logic requires it. The change expands that latter option without making every context value an asynchronous computation.
The template retains ordinary calls
The Jinja 2.10.3 API documentation describes automatic awaiting for function calls in async mode. A template calls the function using its normal syntax. Jinja awaits an awaitable return value as part of evaluating that call. Template authors do not insert Python's await keyword into their expressions.
For an illustrative template context containing an asynchronous summary callable, the expression remains ordinary Jinja.
{% set result = summary() %}
{{ result }}
This example describes the rendering contract, not a built-in Datasette function named summary. A plugin must provide that callable. The documentation also qualifies automatic awaiting as behavior attached to function calls. Placing an awaitable object in an arbitrary attribute does not automatically produce the same result. A function interface gives the renderer the operation it knows how to await.
Jinja's documentation says async mode supports asynchronous iterators in template loops as well. It also explains that enabling the mode generates different template code and imposes overhead even when synchronous methods are used. This is an execution model choice, with a cost, rather than a free annotation on an otherwise unchanged renderer.
Waiting for data still belongs to the request
Asynchronous rendering does not remove the data dependency. A response containing a query result must still wait for that result. What changes is how the rendering operation cooperates with the application's asynchronous execution. The template can suspend at the call instead of requiring the function's work to have completed before rendering starts.
Sequential calls also remain separate calls in the template. Nothing in the release claims that Jinja automatically batches every database operation or executes independent calls concurrently. A template that asks for several results still describes several dependencies. A plugin author can choose an interface that returns a combined result when that best expresses the page's requirements.
The release's plugin test checks an async template function by comparing rendered output with SQLite's own version result. That verifies the completed value reaches the HTML response. It tests the integration through a request, rather than merely checking that the environment flag has been set.
I see this release as a useful extension of Datasette's existing customization model. Templates keep their loading rules and normal expression syntax, while plugin functions gain access to asynchronous rendering. A custom summary can obtain its data when called, and the response contains the completed result when rendering finishes.