=============================== Jinja2 Fragments Documentation =============================== .. image:: https://img.shields.io/pypi/v/jinja2-fragments :alt: PyPI - Version .. image:: https://img.shields.io/pypi/dm/jinja2-fragments :alt: PyPI - Downloads .. image:: https://img.shields.io/github/license/sponsfreixes/jinja2-fragments :alt: License .. raw:: html Overview ======== **jinja2-fragments** is a Python library that enhances `Jinja2 templates `_ by allowing you to render individual blocks from templates. This is particularly useful for modern web applications using `htmx `_ or other JavaScript-based partial page update techniques, where you often need to render just a section of a page rather than the entire page. This library was created to enable the pattern of `Template Fragments `_ with Jinja2, making it easier to maintain a single source template file for both full page and partial rendering. Key Features ------------ * Render specific blocks from Jinja2 templates * Support for rendering multiple blocks at once * Support for both synchronous and asynchronous rendering * Integrations with popular Python web frameworks: * Flask * Starlette * FastAPI (built on Starlette) * Quart (async Flask) * Sanic * Litestar * Natural syntax that follows each framework's conventions * Perfect for use with htmx for dynamic UI updates Quick Start =========== Installation ------------ Install ``jinja2-fragments`` with pip: .. code-block:: bash pip install jinja2-fragments The above also works for framework-specific installations. Basic Usage ----------- Here's a simple example with vanilla Jinja2. Given the following template: .. code-block:: html This is the title

This is a header

{% block content %}

This is the magic number: {{ magic_number }}.

{% endblock %} You can render only the ``content`` block with: .. code-block:: python from jinja2 import Environment, FileSystemLoader, select_autoescape from jinja2_fragments import render_block environment = Environment( loader=FileSystemLoader("my_templates"), autoescape=select_autoescape(("html", "jinja2")), ) rendered_html = render_block( environment, "page.html.jinja2", "content", magic_number=42 ) Which will render: .. code-block:: html

This is the magic number: 42.

Framework Examples ------------------ Each framework has its own integration patterns: .. tabs:: .. tab:: Flask .. code-block:: python from flask import Flask, render_template from jinja2_fragments.flask import render_block app = Flask(__name__) @app.route("/profile/") def profile(username): return render_template("profile.html.jinja2", username=username) @app.route("/profile//details") def profile_details(username): return render_block("profile.html.jinja2", "details", username=username) .. tab:: Quart .. code-block:: python from quart import Quart, render_template from jinja2_fragments.quart import render_block app = Quart(__name__) @app.route("/profile/") async def profile(username): return await render_template("profile.html.jinja2", username=username) @app.route("/profile//details") async def profile_details(username): return await render_block("profile.html.jinja2", "details", username=username) .. tab:: Starlette .. code-block:: python from starlette.applications import Starlette from starlette.requests import Request from starlette.routing import Route from jinja2_fragments.starlette import Jinja2Blocks templates = Jinja2Blocks(directory="templates") async def profile(request: Request): username = request.path_params["username"] return templates.TemplateResponse( request, "profile.html.jinja2", {"username": username} ) async def profile_details(request: Request): username = request.path_params["username"] return templates.TemplateResponse( request, "profile.html.jinja2", {"username": username}, block_name="details" ) routes = [ Route("/profile/{username}", profile), Route("/profile/{username}/details", profile_details), ] app = Starlette(routes=routes) .. tab:: FastAPI .. code-block:: python from fastapi import FastAPI, Request from jinja2_fragments.fastapi import Jinja2Blocks app = FastAPI() templates = Jinja2Blocks(directory="templates") @app.get("/profile/{username}") def profile(request: Request, username: str): return templates.TemplateResponse( request, "profile.html.jinja2", {"username": username} ) @app.get("/profile/{username}/details") def profile_details(request: Request, username: str): return templates.TemplateResponse( request, "profile.html.jinja2", {"username": username}, block_name="details" ) .. tab:: Sanic .. code-block:: python from sanic import Sanic, Request import sanic_ext from jinja2_fragments.sanic import render app = Sanic(__name__) app.extend(config=sanic_ext.Config(templating_path_to_templates="path/to/templates")) @app.route("/profile/") async def profile(request: Request, username: str): return await render("profile.html.jinja2", context={"username": username}) @app.route("/profile//details") async def profile_details(request: Request, username: str): return await render( "profile.html.jinja2", block="content", context={"username": username} ) .. tab:: Litestar .. code-block:: python try: # litestar>=2.13.0 from litestar.plugins.htmx import HTMXRequest except ImportError: # litestar<2.13.0 from litestar.contrib.htmx.request import HTMXRequest from litestar import get, Litestar from litestar.response import Template from litestar.contrib.jinja import JinjaTemplateEngine from litestar.template.config import TemplateConfig from jinja2_fragments.litestar import HTMXBlockTemplate @get("/profile/{username:str}") def profile(request: HTMXRequest, username: str) -> Template: return HTMXBlockTemplate( template_name="profile.html.jinja2", context={"username": username} ) @get("/profile/{username:str}/details") def profile_details(request: HTMXRequest, username: str) -> Template: return HTMXBlockTemplate( template_name="profile.html.jinja2", block_name="details", context={"username": username}, ) app = Litestar( route_handlers=[profile, profile_details], request_class=HTMXRequest, template_config=TemplateConfig( directory="path/to/templates", engine=JinjaTemplateEngine, ), ) .. note:: ``HTMXBlockTemplate`` can be used as a drop-in replacement for Litestar's ``Template`` class. However, passing multiple positional arguments is deprecated and will be removed in a future version. Use ``template_name`` as the only positional argument. .. toctree:: :maxdepth: 2 :caption: User Guide installation basic_usage framework_integrations .. toctree:: :maxdepth: 1 :caption: API Reference api/core api/flask api/quart api/starlette api/fastapi api/sanic api/litestar .. toctree:: :maxdepth: 1 :caption: Development development changelog Indices and Tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search`