Implemented custom pages from pages/ in templates, refs #648

This commit is contained in:
Simon Willison 2020-04-26 10:30:14 -07:00
commit 6add534c65
4 changed files with 37 additions and 3 deletions

View file

@ -17,6 +17,7 @@ from markupsafe import Markup
import jinja2 import jinja2
from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader, escape from jinja2 import ChoiceLoader, Environment, FileSystemLoader, PrefixLoader, escape
from jinja2.environment import Template from jinja2.environment import Template
from jinja2.exceptions import TemplateNotFound
import uvicorn import uvicorn
from .views.base import DatasetteError, ureg, AsgiRouter from .views.base import DatasetteError, ureg, AsgiRouter
@ -745,7 +746,7 @@ class DatasetteRouter(AsgiRouter):
path = "/" + path[len(base_url) :] path = "/" + path[len(base_url) :]
return await super().route_path(scope, receive, send, path) 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 # If URL has a trailing slash, redirect to URL without it
path = scope.get("raw_path", scope["path"].encode("utf8")) path = scope.get("raw_path", scope["path"].encode("utf8"))
if path.endswith(b"/"): if path.endswith(b"/"):
@ -754,7 +755,20 @@ class DatasetteRouter(AsgiRouter):
path += b"?" + scope["query_string"] path += b"?" + scope["query_string"]
await asgi_send_redirect(send, path.decode("latin1")) await asgi_send_redirect(send, path.decode("latin1"))
else: 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:
await asgi_send_html(
send, await self.ds.render_template(template), status=200
)
else:
await self.handle_500(
scope, receive, send, exception or NotFound("404")
)
async def handle_500(self, scope, receive, send, exception): async def handle_500(self, scope, receive, send, exception):
title = None title = None

View file

@ -119,11 +119,13 @@ class AsgiRouter:
new_scope = dict(scope, url_route={"kwargs": match.groupdict()}) new_scope = dict(scope, url_route={"kwargs": match.groupdict()})
try: try:
return await view(new_scope, receive, send) return await view(new_scope, receive, send)
except NotFound as exception:
return await self.handle_404(scope, receive, send, exception)
except Exception as exception: except Exception as exception:
return await self.handle_500(scope, receive, send, exception) return await self.handle_500(scope, receive, send, exception)
return await self.handle_404(scope, receive, send) return await self.handle_404(scope, receive, send)
async def handle_404(self, scope, receive, send): async def handle_404(self, scope, receive, send, exception=None):
await send( await send(
{ {
"type": "http.response.start", "type": "http.response.start",

View file

@ -28,6 +28,7 @@ from datasette.utils.asgi import (
AsgiRouter, AsgiRouter,
AsgiView, AsgiView,
NotFound, NotFound,
NotFound,
Response, Response,
) )

View file

@ -1241,3 +1241,20 @@ def test_base_url_config(base_url, path):
"href_or_src": href, "href_or_src": href,
"element_parent": str(el.parent), "element_parent": str(el.parent),
} }
def test_custom_template_page(tmpdir):
template_dir = tmpdir.mkdir("page-templates")
pages_dir = template_dir.mkdir("pages")
(pages_dir / "about.html").write_text("ABOUT!", "utf-8")
nested_dir = pages_dir.mkdir("nested")
(nested_dir / "nest.html").write_text("Nest!", "utf-8")
for client in make_app_client(template_dir=str(template_dir)):
response = client.get("/about")
assert 200 == response.status
assert "ABOUT!" == response.text
response = client.get("/nested/nest")
assert 200 == response.status
assert "Nest!" == response.text
response = client.get("/nested/nest2")
assert 404 == response.status