Skip to content

Instantly share code, notes, and snippets.

@scott2b
Last active November 9, 2020 16:25
Show Gist options
  • Save scott2b/0de7fcd2eccf69cc2f374a9f2b0aa5f2 to your computer and use it in GitHub Desktop.
Save scott2b/0de7fcd2eccf69cc2f374a9f2b0aa5f2 to your computer and use it in GitHub Desktop.
Request template context with messages for Starlette+Jinja2
{% if request.session.messages %}
<ul>
{% for message in request.session.messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{{ request.clear_messages() }}
{% endif %}
"""
A custom template renderer for Starlette which injects the local request object
into the template context and adds session-based messaging.
Requires session middleware to be installed.
Use Templates as you would use Starlette's Jinja2Templates, e.g.:
```
templates = Templates(directory='templates')
```
and:
```
return templates.TemplateResponse(template, context)
```
The local request (must be named `request`) will be injected into the context.
To send 1-shot messages to the user, call:
```
add_message(request, message)
```
"""
import inspect
import types
from starlette.requests import Request
from starlette.templating import Jinja2Templates
def _clear_messages(request):
"""Call from a template after rendering messages to clear out the current
message list. Requires session middleware.
"""
request.session['messages']= []
return ''
def add_message(request, message):
"""Add a message to the session messages list."""
if not 'messages' in request.session:
request.session['messages'] = []
request.session['messages'].append(message)
class Templates(Jinja2Templates):
def TemplateResponse(
self,
name: str,
context: dict,
**kwargs
):
"""Render a template response.
If it exists and is not already set in the context, injects the
request object from the calling scope into the template context.
Adds a clear_messages method to the request instance.
"""
if 'request' in context:
req = context['request']
if isinstance(req, Request):
req.clear_messages = types.MethodType(_clear_messages, req)
else:
frame = inspect.currentframe()
try:
_locals = frame.f_back.f_locals
req = _locals.get('request')
if req is not None and isinstance(req, Request):
context['request'] = req
req.clear_messages = types.MethodType(_clear_messages, req)
finally:
del frame
return super().TemplateResponse(name, context, **kwargs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment