2022-12-29 14:41:41 +00:00
Starlette is not _strictly_ coupled to any particular templating engine, but
2018-11-08 16:14:14 +00:00
Jinja2 provides an excellent choice.
2018-11-06 16:57:57 +00:00
2023-05-31 15:55:08 +00:00
### Jinja2Templates
Signature: `Jinja2Templates(directory, context_processors=None, **env_options)`
* `directory` - A string, [os.Pathlike][pathlike] or a list of strings or [os.Pathlike][pathlike] denoting a directory path.
* `context_processors` - A list of functions that return a dictionary to add to the template context.
* `**env_options` - Additional keyword arguments to pass to the Jinja2 environment.
2019-02-18 13:12:55 +00:00
Starlette provides a simple way to get `jinja2` configured. This is probably
what you want to use by default.
2018-11-06 16:57:57 +00:00
```python
from starlette.applications import Starlette
2019-11-13 12:25:18 +00:00
from starlette.routing import Route, Mount
2019-02-18 13:12:55 +00:00
from starlette.templating import Jinja2Templates
2019-06-17 02:28:04 +00:00
from starlette.staticfiles import StaticFiles
2018-11-06 16:57:57 +00:00
2019-02-18 13:12:55 +00:00
templates = Jinja2Templates(directory='templates')
2018-11-06 16:57:57 +00:00
async def homepage(request):
2023-07-13 07:58:13 +00:00
return templates.TemplateResponse(request, 'index.html')
2019-11-13 12:25:18 +00:00
routes = [
Route('/', endpoint=homepage),
Mount('/static', StaticFiles(directory='static'), name='static')
]
app = Starlette(debug=True, routes=routes)
2018-11-06 16:57:57 +00:00
```
2019-06-17 12:52:43 +00:00
Note that the incoming `request` instance must be included as part of the
2019-02-18 13:38:04 +00:00
template context.
2018-11-06 16:57:57 +00:00
2019-02-18 13:38:04 +00:00
The Jinja2 template context will automatically include a `url_for` function,
so we can correctly hyperlink to other pages within the application.
For example, we can link to static files from within our HTML templates:
2018-11-06 17:03:34 +00:00
```html
2022-12-29 14:41:41 +00:00
< link href = "{{ url_for('static', path='/css/bootstrap.min.css') }}" rel = "stylesheet" / >
2018-11-06 17:03:34 +00:00
```
2019-12-10 14:58:44 +00:00
If you want to use [custom filters][jinja2], you will need to update the `env`
property of `Jinja2Templates` :
```python
from commonmark import commonmark
from starlette.templating import Jinja2Templates
def marked_filter(text):
return commonmark(text)
templates = Jinja2Templates(directory='templates')
templates.env.filters['marked'] = marked_filter
```
2023-06-05 18:20:36 +00:00
## Using custom jinja2.Environment instance
Starlette also accepts a preconfigured [`jinja2.Environment` ](https://jinja.palletsprojects.com/en/3.0.x/api/#api ) instance.
```python
import jinja2
from starlette.templating import Jinja2Templates
env = jinja2.Environment(...)
templates = Jinja2Templates(env=env)
```
2022-12-29 14:41:41 +00:00
## Context processors
A context processor is a function that returns a dictionary to be merged into a template context.
Every function takes only one argument `request` and must return a dictionary to add to the context.
A common use case of template processors is to extend the template context with shared variables.
```python
import typing
from starlette.requests import Request
def app_context(request: Request) -> typing.Dict[str, typing.Any]:
return {'app': request.app}
```
### Registering context templates
Pass context processors to `context_processors` argument of the `Jinja2Templates` class.
```python
import typing
from starlette.requests import Request
from starlette.templating import Jinja2Templates
def app_context(request: Request) -> typing.Dict[str, typing.Any]:
return {'app': request.app}
templates = Jinja2Templates(
directory='templates', context_processors=[app_context]
)
```
!!! info
Asynchronous functions as context processors are not supported.
2019-02-18 13:12:55 +00:00
## Testing template responses
When using the test client, template responses include `.template` and `.context`
attributes.
```python
2022-12-25 18:25:51 +00:00
from starlette.testclient import TestClient
2019-02-18 13:12:55 +00:00
def test_homepage():
client = TestClient(app)
response = client.get("/")
assert response.status_code == 200
assert response.template.name == 'index.html'
assert "request" in response.context
```
2022-01-19 13:38:57 +00:00
## Customizing Jinja2 Environment
`Jinja2Templates` accepts all options supported by Jinja2 `Environment` .
2022-02-09 09:02:30 +00:00
This will allow more control over the `Environment` instance created by Starlette.
2022-01-19 13:38:57 +00:00
For the list of options available to `Environment` you can check Jinja2 documentation [here ](https://jinja.palletsprojects.com/en/3.0.x/api/#jinja2.Environment )
```python
from starlette.templating import Jinja2Templates
templates = Jinja2Templates(directory='templates', autoescape=False, auto_reload=True)
```
2018-11-06 16:57:57 +00:00
## Asynchronous template rendering
Jinja2 supports async template rendering, however as a general rule
we'd recommend that you keep your templates free from logic that invokes
database lookups, or other I/O operations.
2019-02-18 13:38:04 +00:00
Instead we'd recommend that you ensure that your endpoints perform all I/O,
2018-11-06 16:57:57 +00:00
for example, strictly evaluate any database queries within the view and
include the final results in the context.
2019-12-10 14:58:44 +00:00
2022-02-08 15:19:02 +00:00
[jinja2]: https://jinja.palletsprojects.com/en/3.0.x/api/?highlight=environment#writing-filters
2023-05-31 15:55:08 +00:00
[pathlike]: https://docs.python.org/3/library/os.html#os.PathLike