Skip to main content

Simple reuse of partial HTML page templates in the Jinja template language for Python web frameworks.

Project description

Jinja Partials

Simple reuse of partial HTML page templates in the Jinja template language for Python web frameworks. (There is also a Pyramid/Chameleon version here.)

Overview

When building real-world web apps with Jinja2, it's easy to end up with repeated HTML fragments. Just like organizing code for reuse, it would be ideal to reuse smaller sections of HTML template code. That's what this library is all about.

Documentation

The full documentation is available at mkennedy.codes/docs/jinja-partials.

Supported Frameworks

Jinja Partials has specific support for the most popular Python web frameworks:

  • Flask - register_extensions(app)
  • FastAPI - register_fastapi_extensions(app, templates)
  • Starlette - register_starlette_extensions(templates, app=app)
  • Quart - register_quart_extensions(app)
  • Any Jinja2 environment - register_environment(env)

Examples

This project includes example applications for each supported framework in the examples folder:

Each example demonstrates reusable partial templates. The screenshot below is from the Flask example:

Installation

It's just pip install jinja-partials and you're all set with this pure Python package.

Requires Python 3.10 or newer (on older versions of Python, pip will install an earlier release that predates the FastAPI, Starlette, and Quart support described here).

Usage

Using the library is easy. Register jinja_partials with your framework once at app startup.

Flask

import flask
import jinja_partials

app = flask.Flask(__name__)
jinja_partials.register_extensions(app)

FastAPI

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)

Starlette

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)

Quart

from quart import Quart
import jinja_partials

app = Quart(__name__)
jinja_partials.register_quart_extensions(app)

Direct Jinja2 Environment

For any other use case, register directly with a Jinja2 environment:

from jinja2 import Environment, FileSystemLoader
import jinja_partials

environment = Environment(loader=FileSystemLoader("templates"))
jinja_partials.register_environment(environment, markup=True)

Using the Jinja2 Extension (Declarative)

Alternatively, you can use the PartialsJinjaExtension for a more declarative approach.

For Flask Applications

With Flask, add the extension to your app's Jinja environment:

import flask
import jinja_partials

app = flask.Flask(__name__)

# Declarative registration with Flask
app.jinja_env.add_extension('jinja_partials.PartialsJinjaExtension')

# Alternative: traditional registration
# jinja_partials.register_extensions(app)

Note: With the extension approach, partials render directly through the Jinja environment rather than flask.render_template. That means Flask context processors (@app.context_processor) and the template_rendered signal do not apply inside partials. If your partials depend on those, use jinja_partials.register_extensions(app).

For Standalone Jinja2 Environments

For direct Jinja2 usage (without Flask):

from jinja2 import Environment, FileSystemLoader

# Declarative registration - extension automatically registers render_partial
environment = Environment(
    loader=FileSystemLoader("tests/test_templates"),
    extensions=["jinja_partials.PartialsJinjaExtension"]
)
# render_partial is now available in templates, no additional setup needed!

When to Use the Extension Approach

This declarative approach is especially useful when:

  • Working with frameworks that configure Jinja2 environments declaratively
  • You want cleaner, more explicit dependency management
  • Integrating with other Jinja2 extensions
  • Using standalone Jinja2 environments outside of Flask

The extension automatically enables markup support by default, ensuring that your partial templates return properly escaped Markup objects.

Template Usage

Next, you define your main HTML (Jinja2) templates as usual. Then define your partial templates. I recommend locating and naming them accordingly:

├── templates
│   ├── home
│   │   ├── index.html
│   │   └── listing.html
│   └── shared
│       ├── _layout.html
│       └── partials
│           ├── video_image.html
│           └── video_square.html

Notice the partials subfolder in the templates/shared folder.

The templates are just HTML fragments. Here is a stand-alone one for the YouTube thumbnail from the example app:

<img src="https://img.youtube.com/vi/{{ video.id }}/maxresdefault.jpg"
     class="img img-responsive {{ (classes | default([])) | join(' ') }}"
     alt="{{ video.title }}"
     title="{{ video.title }}">

Notice that an object called video is passed in as the model, along with an optional list of CSS classes.

Templates can also be nested. Here is the whole single video fragment with the image as well as other info linking out to YouTube:

<div>
    <a href="https://www.youtube.com/watch?v={{ video.id }}" target="_blank">
        {{ render_partial('shared/partials/video_image.html', video=video) }}
    </a>
    <a href="https://www.youtube.com/watch?v={{ video.id }}" target="_blank"
       class="author">{{ video.author }}</a>
    <div class="views">{{ "{:,}".format(video.views) }} views</div>
</div>

Now you see the render_partial() method. It takes the subpath into the templates folder and any model data passed in as keyword arguments.

We can finally generate the list of video blocks as follows:

{% for v in videos %}

    <div class="col-md-3 video">
        {{ render_partial('shared/partials/video_square.html', video=v) }}
    </div>

{% endfor %}

This time, we reframe each item in the list from the outer template (called v) as the video model in the inner HTML section.

Why not just use include or macro from Jinja?

The short answer is they are nearly the same, but both fall short in different ways. For a more detailed response, see the discussion on issue #1

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jinja_partials-0.3.2.tar.gz (3.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jinja_partials-0.3.2-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file jinja_partials-0.3.2.tar.gz.

File metadata

  • Download URL: jinja_partials-0.3.2.tar.gz
  • Upload date:
  • Size: 3.0 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jinja_partials-0.3.2.tar.gz
Algorithm Hash digest
SHA256 4ecaeb02735b48dd7643d0cb6f112e4669fa69cf83ce1c601b6f3c882283d013
MD5 5732371a7b178ae858fcf540b66b7984
BLAKE2b-256 07d3ef7bea796d230199e6b36d4466148d92503d937d82a9f55f54b14e81708e

See more details on using hashes here.

File details

Details for the file jinja_partials-0.3.2-py3-none-any.whl.

File metadata

  • Download URL: jinja_partials-0.3.2-py3-none-any.whl
  • Upload date:
  • Size: 9.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for jinja_partials-0.3.2-py3-none-any.whl
Algorithm Hash digest
SHA256 331219b75db8b8b5289a8e0aace2854c74d36b3b993ba960748f7f2ed049743b
MD5 d62a245237e7339f49e4a0b7c117755f
BLAKE2b-256 8c7feab7def87914f272500236e3d765649c64a7bc83e24cf1b8303f76bfc6cf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page