Templates
Starlette is notstrictly coupled to any particular templating engine, butJinja2 provides an excellent choice.
Jinja2Templates
Signature:Jinja2Templates(directory, context_processors=None, **env_options)
directory- A string,os.Pathlike or a list of strings oros.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.
Starlette provides a simple way to getjinja2 configured. This is probablywhat you want to use by default.
fromstarlette.applicationsimportStarlettefromstarlette.routingimportRoute,Mountfromstarlette.templatingimportJinja2Templatesfromstarlette.staticfilesimportStaticFilestemplates=Jinja2Templates(directory='templates')asyncdefhomepage(request):returntemplates.TemplateResponse(request,'index.html')routes=[Route('/',endpoint=homepage),Mount('/static',StaticFiles(directory='static'),name='static')]app=Starlette(debug=True,routes=routes)Note that the incomingrequest instance must be included as part of thetemplate context.
The Jinja2 template context will automatically include aurl_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:
<linkhref="{{ url_for('static', path='/css/bootstrap.min.css') }}"rel="stylesheet"/>If you want to usecustom filters, you will need to update theenvproperty ofJinja2Templates:
fromcommonmarkimportcommonmarkfromstarlette.templatingimportJinja2Templatesdefmarked_filter(text):returncommonmark(text)templates=Jinja2Templates(directory='templates')templates.env.filters['marked']=marked_filterUsing custom jinja2.Environment instance
Starlette also accepts a preconfiguredjinja2.Environment instance.
importjinja2fromstarlette.templatingimportJinja2Templatesenv=jinja2.Environment(...)templates=Jinja2Templates(env=env)Context processors
A context processor is a function that returns a dictionary to be merged into a template context.Every function takes only one argumentrequest 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.
importtypingfromstarlette.requestsimportRequestdefapp_context(request:Request)->typing.Dict[str,typing.Any]:return{'app':request.app}Registering context templates
Pass context processors tocontext_processors argument of theJinja2Templates class.
importtypingfromstarlette.requestsimportRequestfromstarlette.templatingimportJinja2Templatesdefapp_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.
Testing template responses
When using the test client, template responses include.template and.contextattributes.
fromstarlette.testclientimportTestClientdeftest_homepage():client=TestClient(app)response=client.get("/")assertresponse.status_code==200assertresponse.template.name=='index.html'assert"request"inresponse.contextCustomizing Jinja2 Environment
Jinja2Templates accepts all options supported by Jinja2Environment.This will allow more control over theEnvironment instance created by Starlette.
For the list of options available toEnvironment you can check Jinja2 documentationhere
fromstarlette.templatingimportJinja2Templatestemplates=Jinja2Templates(directory='templates',autoescape=False,auto_reload=True)Asynchronous template rendering
Jinja2 supports async template rendering, however as a general rulewe'd recommend that you keep your templates free from logic that invokesdatabase lookups, or other I/O operations.
Instead we'd recommend that you ensure that your endpoints perform all I/O,for example, strictly evaluate any database queries within the view andinclude the final results in the context.