Refactored .custom_sql() method to new QueryView class

Refs #698
pull/719/head
Simon Willison 2020-04-02 18:12:13 -07:00
rodzic b07312c2b3
commit 07e208cc6d
3 zmienionych plików z 119 dodań i 105 usunięć

Wyświetl plik

@ -461,104 +461,3 @@ class DataView(BaseView):
if self.ds.cors: if self.ds.cors:
response.headers["Access-Control-Allow-Origin"] = "*" response.headers["Access-Control-Allow-Origin"] = "*"
return response return response
async def custom_sql(
self,
request,
database,
hash,
sql,
editable=True,
canned_query=None,
metadata=None,
_size=None,
):
params = request.raw_args
if "sql" in params:
params.pop("sql")
if "_shape" in params:
params.pop("_shape")
# Extract any :named parameters
named_parameters = self.re_named_parameter.findall(sql)
named_parameter_values = {
named_parameter: params.get(named_parameter) or ""
for named_parameter in named_parameters
}
# Set to blank string if missing from params
for named_parameter in named_parameters:
if named_parameter not in params:
params[named_parameter] = ""
extra_args = {}
if params.get("_timelimit"):
extra_args["custom_time_limit"] = int(params["_timelimit"])
if _size:
extra_args["page_size"] = _size
results = await self.ds.execute(
database, sql, params, truncate=True, **extra_args
)
columns = [r[0] for r in results.description]
templates = ["query-{}.html".format(to_css_class(database)), "query.html"]
if canned_query:
templates.insert(
0,
"query-{}-{}.html".format(
to_css_class(database), to_css_class(canned_query)
),
)
async def extra_template():
display_rows = []
for row in results.rows:
display_row = []
for column, value in zip(results.columns, row):
display_value = value
# Let the plugins have a go
# pylint: disable=no-member
plugin_value = pm.hook.render_cell(
value=value,
column=column,
table=None,
database=database,
datasette=self.ds,
)
if plugin_value is not None:
display_value = plugin_value
else:
if value in ("", None):
display_value = jinja2.Markup(" ")
elif is_url(str(display_value).strip()):
display_value = jinja2.Markup(
'<a href="{url}">{url}</a>'.format(
url=jinja2.escape(value.strip())
)
)
display_row.append(display_value)
display_rows.append(display_row)
return {
"display_rows": display_rows,
"custom_sql": True,
"named_parameter_values": named_parameter_values,
"editable": editable,
"canned_query": canned_query,
"metadata": metadata,
"config": self.ds.config_dict(),
"request": request,
"path_with_added_args": path_with_added_args,
"path_with_removed_args": path_with_removed_args,
"hide_sql": "_hide_sql" in params,
}
return (
{
"database": database,
"rows": results.rows,
"truncated": results.truncated,
"columns": columns,
"query": {"sql": sql, "params": params},
},
extra_template,
templates,
)

Wyświetl plik

@ -1,7 +1,15 @@
import os import os
import jinja2
from datasette.utils import to_css_class, validate_sql_select from datasette.utils import (
to_css_class,
validate_sql_select,
is_url,
path_with_added_args,
path_with_removed_args,
)
from datasette.utils.asgi import AsgiFileDownload from datasette.utils.asgi import AsgiFileDownload
from datasette.plugins import pm
from .base import DatasetteError, DataView from .base import DatasetteError, DataView
@ -18,7 +26,7 @@ class DatabaseView(DataView):
raise DatasetteError("sql= is not allowed", status=400) raise DatasetteError("sql= is not allowed", status=400)
sql = request.raw_args.pop("sql") sql = request.raw_args.pop("sql")
validate_sql_select(sql) validate_sql_select(sql)
return await self.custom_sql( return await QueryView(self.ds).data(
request, database, hash, sql, _size=_size, metadata=metadata request, database, hash, sql, _size=_size, metadata=metadata
) )
@ -85,3 +93,108 @@ class DatabaseDownload(DataView):
filename=os.path.basename(filepath), filename=os.path.basename(filepath),
content_type="application/octet-stream", content_type="application/octet-stream",
) )
class QueryView(DataView):
name = "query"
async def data(
self,
request,
database,
hash,
sql,
editable=True,
canned_query=None,
metadata=None,
_size=None,
):
params = request.raw_args
if "sql" in params:
params.pop("sql")
if "_shape" in params:
params.pop("_shape")
# Extract any :named parameters
named_parameters = self.re_named_parameter.findall(sql)
named_parameter_values = {
named_parameter: params.get(named_parameter) or ""
for named_parameter in named_parameters
}
# Set to blank string if missing from params
for named_parameter in named_parameters:
if named_parameter not in params:
params[named_parameter] = ""
extra_args = {}
if params.get("_timelimit"):
extra_args["custom_time_limit"] = int(params["_timelimit"])
if _size:
extra_args["page_size"] = _size
results = await self.ds.execute(
database, sql, params, truncate=True, **extra_args
)
columns = [r[0] for r in results.description]
templates = ["query-{}.html".format(to_css_class(database)), "query.html"]
if canned_query:
templates.insert(
0,
"query-{}-{}.html".format(
to_css_class(database), to_css_class(canned_query)
),
)
async def extra_template():
display_rows = []
for row in results.rows:
display_row = []
for column, value in zip(results.columns, row):
display_value = value
# Let the plugins have a go
# pylint: disable=no-member
plugin_value = pm.hook.render_cell(
value=value,
column=column,
table=None,
database=database,
datasette=self.ds,
)
if plugin_value is not None:
display_value = plugin_value
else:
if value in ("", None):
display_value = jinja2.Markup("&nbsp;")
elif is_url(str(display_value).strip()):
display_value = jinja2.Markup(
'<a href="{url}">{url}</a>'.format(
url=jinja2.escape(value.strip())
)
)
display_row.append(display_value)
display_rows.append(display_row)
return {
"display_rows": display_rows,
"custom_sql": True,
"named_parameter_values": named_parameter_values,
"editable": editable,
"canned_query": canned_query,
"metadata": metadata,
"config": self.ds.config_dict(),
"request": request,
"path_with_added_args": path_with_added_args,
"path_with_removed_args": path_with_removed_args,
"hide_sql": "_hide_sql" in params,
}
return (
{
"database": database,
"rows": results.rows,
"truncated": results.truncated,
"columns": columns,
"query": {"sql": sql, "params": params},
},
extra_template,
templates,
)

Wyświetl plik

@ -26,6 +26,7 @@ from datasette.utils import (
from datasette.utils.asgi import NotFound from datasette.utils.asgi import NotFound
from datasette.filters import Filters from datasette.filters import Filters
from .base import DataView, DatasetteError, ureg from .base import DataView, DatasetteError, ureg
from .database import QueryView
LINK_WITH_LABEL = ( LINK_WITH_LABEL = (
'<a href="{base_url}{database}/{table}/{link_id}">{label}</a>&nbsp;<em>{id}</em>' '<a href="{base_url}{database}/{table}/{link_id}">{label}</a>&nbsp;<em>{id}</em>'
@ -221,8 +222,8 @@ class TableView(RowTableShared):
_size=None, _size=None,
): ):
canned_query = self.ds.get_canned_query(database, table) canned_query = self.ds.get_canned_query(database, table)
if canned_query is not None: if canned_query:
return await self.custom_sql( return await QueryView(self.ds).data(
request, request,
database, database,
hash, hash,
@ -231,6 +232,7 @@ class TableView(RowTableShared):
editable=False, editable=False,
canned_query=table, canned_query=table,
) )
db = self.ds.databases[database] db = self.ds.databases[database]
is_view = bool(await db.get_view_definition(table)) is_view = bool(await db.get_view_definition(table))
table_exists = bool(await db.table_exists(table)) table_exists = bool(await db.table_exists(table))