Skip to content

Server Side Rendering (SSR)

Server-side templating refers to a web application's ability to generate HTML pages using templates and dynamic variables. By default, BlackSheep uses the Jinja2 library library developed by the Pallets team, but it also supports custom renderers.

This page covers:

  • Configuring server-side templating.
  • Returning views using response functions.
  • Returning views with MVC features.
  • Using alternatives to Jinja2.

Info

The BlackSheep MVC project template includes a ready-to-use solution having an application with templates and layout configured.

Configuration

This example illustrates how to use Jinja2 templating engine with BlackSheep:

from blacksheep import Application, get
from blacksheep.server.responses import view

app = Application()


@get("/")
def home():
    return view("home", {"example": "Hello", "foo": "World"})

The expected folder structure for this example:

⬑ app
     ⬑ views
          home.jinja   <-- template file loaded by `view` function
     __init__.py

server.py

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
</head>
<body>
  <h1>{{example}}</h1>
  <p>{{foo}}</p>
</body>
</html>

Async mode

It is possible to enable Jinja2 async mode, in the following way:

from blacksheep import Application, get
from blacksheep.server.rendering.jinja2 import JinjaRenderer
from blacksheep.server.responses import view_async
from blacksheep.settings.html import html_settings

app = Application()
html_settings.use(JinjaRenderer(enable_async=True))

@get("/")
async def home():
    return await view_async("home", {"example": "Hello", "foo": "World"})

Loading templates

It is possible to load templates by name including .jinja, or without file extension; .jinja extension is added automatically if no extension is specified. The extension must be lowercase.

@get("/")
async def home(request):
    return view("home.jinja", {"example": "Hello", "foo": "World"})


# or...


@get("/")
async def home(request):
    return view("home", {"example": "Hello", "foo": "World"})

Helpers and filters

To configure custom helpers and filters for Jinja, access the renderer through blacksheep.settings.html.html_settings:

.
├── app
│   ├── __init__.py
│   └── views
│       └── index.jinja
└── server.py
from datetime import datetime

from blacksheep.server import Application
from blacksheep.server.rendering.jinja2 import JinjaRenderer
from blacksheep.settings.html import html_settings

def configure_templating(
    application: Application
) -> None:
    """
    Configures server side rendering for HTML views.
    """
    renderer = html_settings.renderer
    assert isinstance(renderer, JinjaRenderer)

    def get_copy():
        now = datetime.now()
        return "{} {}".format(now.year, "Example")

    helpers = {"_": lambda x: x, "copy": get_copy}

    env = renderer.env
    env.globals.update(helpers)
<!-- index.jinja -->
<p>Hello, World!</p>
{{ copy() }}

Using alternatives to Jinja2

To use alternative classes for server-side rendering:

  1. Define an implementation of blacksheep.server.rendering.abc.Renderer
  2. Configure it using from blacksheep.settings.html import html_settings
from blacksheep.server.csrf import AntiForgeryHandler
from blacksheep.settings.html import html_settings
from blacksheep.server.rendering.abc import Renderer


class CustomRenderer(Renderer):

    def render(self, template: str, model, **kwargs) -> str:
        """Renders a view synchronously."""
        ...

    async def render_async(self, template: str, model, **kwargs) -> str:
        """Renders a view asynchronously."""
        ...

    def bind_anti_forgery_handler(self, handler: AntiForgeryHandler) -> None:
        """
        Applies extensions for an anti-forgery handler.

        This method can be used to generate HTML fragments containing
        anti-forgery tokens, for the built-in implementation of AF validation.
        """


html_settings.use(CustomRenderer())

Last modified on: 2025-04-22 08:29:25

RP
EW
RV