New JSON design for query views (#2118)

* Refs #2111, closes #2110
* New Context dataclass/subclass mechanism, refs #2127
* Define QueryContext and extract get_tables() method, refs #2127
* Fix OPTIONS bug by porting DaatbaseView to be a View subclass
* Expose async_view_for_class.view_class for test_routes test
* Error/truncated aruments for renderers, closes #2130
This commit is contained in:
Simon Willison 2023-08-07 18:47:39 -07:00 committed by GitHub
commit 1377a290cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 579 additions and 112 deletions

View file

@ -1,7 +1,8 @@
import asyncio
from typing import Sequence, Union, Tuple, Optional, Dict, Iterable
from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple, Union
import asgi_csrf
import collections
import dataclasses
import datetime
import functools
import glob
@ -33,6 +34,7 @@ from jinja2 import (
from jinja2.environment import Template
from jinja2.exceptions import TemplateNotFound
from .views import Context
from .views.base import ureg
from .views.database import database_download, DatabaseView, TableCreateView
from .views.index import IndexView
@ -1115,7 +1117,11 @@ class Datasette:
)
async def render_template(
self, templates, context=None, request=None, view_name=None
self,
templates: Union[List[str], str, Template],
context: Optional[Union[Dict[str, Any], Context]] = None,
request: Optional[Request] = None,
view_name: Optional[str] = None,
):
if not self._startup_invoked:
raise Exception("render_template() called before await ds.invoke_startup()")
@ -1126,6 +1132,8 @@ class Datasette:
if isinstance(templates, str):
templates = [templates]
template = self.jinja_env.select_template(templates)
if dataclasses.is_dataclass(context):
context = dataclasses.asdict(context)
body_scripts = []
# pylint: disable=no-member
for extra_script in pm.hook.extra_body_script(
@ -1368,7 +1376,8 @@ class Datasette:
r"/(?P<database>[^\/\.]+)\.db$",
)
add_route(
DatabaseView.as_view(self), r"/(?P<database>[^\/\.]+)(\.(?P<format>\w+))?$"
wrap_view(DatabaseView, self),
r"/(?P<database>[^\/\.]+)(\.(?P<format>\w+))?$",
)
add_route(TableCreateView.as_view(self), r"/(?P<database>[^\/\.]+)/-/create$")
add_route(
@ -1707,6 +1716,7 @@ def wrap_view_class(view_class, datasette):
datasette=datasette,
)
async_view_for_class.view_class = view_class
return async_view_for_class