jinja_partials

repository·main·Indexed 42 days ago

https://github.com/mikeckennedy/jinja_partials

A library for reusing small HTML fragments (partials) within Jinja2 templates for Python web frameworks. It provides integration for Flask, FastAPI, Starlette, and Quart, supporting both synchronous and asynchronous rendering. Version 0.3.2 requires Python 3.10 or higher and includes features like lifecycle-managed async rendering and a declarative PartialsJinjaExtension.

Tokens
8.3K
Snippets
37
Records
50
Agent score
44%

What's inside jinja_partials

  1. Use the declarative PartialsJinjaExtension

    main

    You can use PartialsJinjaExtension for a declarative approach. This is useful for frameworks that configure Jinja2 environments declaratively or when using standalone Jinja2 environments.

    Important Note for Flask users: When using the extension approach, partials render directly through the Jinja environment rather than flask.render_template. Consequently, Flask context processors (@app.context_processor) and the template_rendered signal do not apply inside partials. If your partials depend on these, use the traditional register_extensions(app) method instead.

    # For Flask
    app.jinja_env.add_extension('jinja_partials.PartialsJinjaExtension')
    
    # For Standalone Jinja2
    from jinja2 import Environment, FileSystemLoader
    environment = Environment(
        loader=FileSystemLoader("templates"),
        extensions=["jinja_partials.PartialsJinjaExtension"]
    )
  2. How partials and async environments work together

    main

    In async frameworks (FastAPI, Starlette, Quart), jinja_partials installs a renderer that executes each partial's render_async on a thread pool (default max_workers=4).

    The Page-Level Rule: When using an async Jinja environment, you must render the main page using await template.render_async(...) and return an HTMLResponse. Do not use TemplateResponse(...) as it calls asyncio.run() inside the event loop and will crash.

    @app.get('/')
    async def index() -> HTMLResponse:
        template = templates.get_template('home/index.html')
        return HTMLResponse(await template.render_async(items=items))
  3. How partials and Jinja inheritance interact

    main

    Partials are intended to complement, not replace, Jinja's inheritance model. You should continue to use {% extends %} for page-level layouts. Use render_partial to handle reusable fragments (components) within those layouts or pages.

    A common project layout convention is to store partials in a templates/shared/partials/ directory.

  4. Register jinja_partials with a Quart application

    main

    Use register_quart_extensions() to integrate jinja_partials into a Quart application. This function sets up a dedicated ThreadPoolExecutor to handle the rendering of partials within Quart's asynchronous environment.

    The executor is managed by the application lifecycle: it is created when the app starts serving and shut down when the app stops. This ensures that if an application fails to start, the executor is cleaned up and replaced on the next attempt. If called outside of a serving cycle, the library falls back to a per-registration executor using the same max_workers configuration.

    register_quart_extensions(
        app,
        max_workers=4,
    )
  5. Enable PartialsJinjaExtension in a Jinja2 environment

    main

    To use the render_partial functionality in a standard Jinja2 environment, add jinja_partials.PartialsJinjaExtension to your environment's extensions list. This makes render_partial available as a global function within your templates. By default, markup is enabled.

    from jinja2 import Environment
    
    env = Environment(extensions=["jinja_partials.PartialsJinjaExtension"])
  6. Register jinja-partials with Starlette

    main

    For Starlette, use register_starlette_extensions, passing the Jinja2Templates instance and the app instance.

    from starlette.applications import Starlette
    from starlette.templating import Jinja2Templates
    import jinja_partials
    
    templates = Jinja2Templates(directory="templates")
    app = Starlette(routes=[...])
    
    jinja_partials.register_starlette_extensions(templates, app=app)
  7. Register jinja-partials with FastAPI

    main

    For FastAPI, use register_fastapi_extensions, passing both the FastAPI app instance and the Jinja2Templates instance.

    from fastapi import FastAPI
    from fastapi.templating import Jinja2Templates
    import jinja_partials
    
    app = FastAPI()
    templates = Jinja2Templates(directory="templates")
    
    jinja_partials.register_fastapi_extensions(app, templates)
  8. Render partials in Jinja templates using render_partial()

    main

    Once registered, you can render reusable HTML fragments within your templates using the render_partial() function.

    Syntax: {{ render_partial('path/to/partial.html', key=value) }}

    • Path: The subpath to the partial template relative to your templates directory.
    • Arguments: Any model data or variables you want to pass into the partial should be provided as keyword arguments.
    {# Example: Rendering a video square partial inside a loop #}
    {% for v in videos %}
        <div class="col-md-3 video">
            {{ render_partial('shared/partials/video_square.html', video=v) }}
        </div>
    {% endfor %}
  9. Register jinja-partials with Flask

    main

    To use partials in a Flask application, use the register_extensions method. This is the traditional registration method that ensures Flask context processors (@app.context_processor) and the template_rendered signal work correctly inside partials.

    import flask
    import jinja_partials
    
    app = flask.Flask(__name__)
    jinja_partials.register_extensions(app)
  10. Use async rendering in async environments

    main

    When working in an async framework (FastAPI, Starlette, or Quart), ensure you use render_async or ensure your environment is configured with enable_async=True.

    In version 0.3.1 and later, the library fixed the asyncio.run() cannot be called from a running event loop error that previously occurred when calling render_partial in async environments. Templates compiled with enable_async=True are now designed to render correctly via a ThreadPoolExecutor managed by the framework extensions.

    # Example pattern for async environments
    # Ensure templates are compiled with enable_async=True
    # Use render_async to avoid event loop conflicts
    await render_async(templates, 'template_name.html', **context)
  11. Register jinja_partials with your web framework

    main

    To use partials, you must register the extension once at application startup. The registration method depends on the framework you are using:

    • Flask: jinja_partials.register_extensions(app)
    • Quart: jinja_partials.register_quart_extensions(app)
    • FastAPI: jinja_partials.register_fastapi_extensions(app, templates)
    • Starlette: jinja_partials.register_starlette_extensions(templates, app=app)
    • Plain Jinja2: jinja_partials.register_environment(env, markup=True)
    • Declarative (Jinja2 Extension): Use extensions=['jinja_partials.PartialsJinjaExtension'] in your Environment configuration.
    # Flask example
    import flask
    import jinja_partials
    
    app = flask.Flask(__name__)
    jinja_partials.register_extensions(app)