Mechanism for creating custom pages using templates

Closes #648
This commit is contained in:
Simon Willison 2020-04-26 11:46:43 -07:00 committed by GitHub
commit 304e7b1d9f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 208 additions and 3 deletions

View file

@ -17,6 +17,7 @@ from markupsafe import Markup
import jinja2
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader, escape
from jinja2.environment import Template
from jinja2.exceptions import TemplateNotFound
import uvicorn
from .views.base import DatasetteError, ureg, AsgiRouter
@ -745,7 +746,7 @@ class DatasetteRouter(AsgiRouter):
path = "/" + path[len(base_url) :]
return await super().route_path(scope, receive, send, path)
async def handle_404(self, scope, receive, send):
async def handle_404(self, scope, receive, send, exception=None):
# If URL has a trailing slash, redirect to URL without it
path = scope.get("raw_path", scope["path"].encode("utf8"))
if path.endswith(b"/"):
@ -754,7 +755,54 @@ class DatasetteRouter(AsgiRouter):
path += b"?" + scope["query_string"]
await asgi_send_redirect(send, path.decode("latin1"))
else:
await super().handle_404(scope, receive, send)
# Is there a pages/* template matching this path?
template_path = os.path.join("pages", *scope["path"].split("/")) + ".html"
try:
template = self.ds.jinja_env.select_template([template_path])
except TemplateNotFound:
template = None
if template:
headers = {}
status = [200]
def custom_header(name, value):
headers[name] = value
return ""
def custom_status(code):
status[0] = code
return ""
def custom_redirect(location, code=302):
status[0] = code
headers["Location"] = location
return ""
body = await self.ds.render_template(
template,
{
"custom_header": custom_header,
"custom_status": custom_status,
"custom_redirect": custom_redirect,
},
view_name="page",
)
# Pull content-type out into separate parameter
content_type = "text/html"
matches = [k for k in headers if k.lower() == "content-type"]
if matches:
content_type = headers[matches[0]]
await asgi_send(
send,
body,
status=status[0],
headers=headers,
content_type=content_type,
)
else:
await self.handle_500(
scope, receive, send, exception or NotFound("404")
)
async def handle_500(self, scope, receive, send, exception):
title = None