kopia lustrzana https://github.com/simonw/datasette
New ?_json=colname argument for returning unescaped JSON
Also extracted docs for special JSON arguments into a new section. Closes #31custom-router
rodzic
02870e5731
commit
76d11eb768
|
@ -183,6 +183,15 @@ class BaseView(RenderMixin):
|
|||
forward_querystring=False,
|
||||
)
|
||||
|
||||
# Handle the _json= parameter which may modify data["rows"]
|
||||
json_cols = []
|
||||
if "_json" in request.args:
|
||||
json_cols = request.args["_json"]
|
||||
if json_cols and "rows" in data and "columns" in data:
|
||||
data["rows"] = convert_specific_columns_to_json(
|
||||
data["rows"], data["columns"], json_cols,
|
||||
)
|
||||
|
||||
# Deal with the _shape option
|
||||
shape = request.args.get("_shape", "arrays")
|
||||
if shape == "arrayfirst":
|
||||
|
@ -323,3 +332,22 @@ class BaseView(RenderMixin):
|
|||
"canned_query": canned_query,
|
||||
"config": self.ds.config,
|
||||
}, templates
|
||||
|
||||
|
||||
def convert_specific_columns_to_json(rows, columns, json_cols):
|
||||
json_cols = set(json_cols)
|
||||
if not json_cols.intersection(columns):
|
||||
return rows
|
||||
new_rows = []
|
||||
for row in rows:
|
||||
new_row = []
|
||||
for value, column in zip(row, columns):
|
||||
if column in json_cols:
|
||||
try:
|
||||
value = json.loads(value)
|
||||
except (TypeError, ValueError) as e:
|
||||
print(e)
|
||||
pass
|
||||
new_row.append(value)
|
||||
new_rows.append(new_row)
|
||||
return new_rows
|
||||
|
|
|
@ -131,6 +131,33 @@ this format.
|
|||
The ``object`` keys are always strings. If your table has a compound primary
|
||||
key, the ``object`` keys will be a comma-separated string.
|
||||
|
||||
Special JSON arguments
|
||||
----------------------
|
||||
|
||||
Every Datasette endpoint that can return JSON also accepts the following
|
||||
querystring arguments:
|
||||
|
||||
``?_shape=SHAPE``
|
||||
The shape of the JSON to return, documented above.
|
||||
|
||||
``?_json=COLUMN1&_json=COLUMN2``
|
||||
If any of your SQLite columns contain JSON values, you can use one or more
|
||||
``_json=`` parameters to request that those columns be returned as regular
|
||||
JSON. Without this argument those columns will be returned as JSON objects
|
||||
that have been double-encoded into a JSON string value.
|
||||
|
||||
Compare `this query without the argument <https://fivethirtyeight.datasettes.com/fivethirtyeight.json?sql=select+%27{%22this+is%22%3A+%22a+json+object%22}%27+as+d&_shape=array>`_ to `this query using the argument <https://fivethirtyeight.datasettes.com/fivethirtyeight.json?sql=select+%27{%22this+is%22%3A+%22a+json+object%22}%27+as+d&_shape=array&_json=d>`_
|
||||
|
||||
``?_timelimit=MS``
|
||||
Sets a custom time limit for the query in ms. You can use this for optimistic
|
||||
queries where you would like Datasette to give up if the query takes too
|
||||
long, for example if you want to implement autocomplete search but only if
|
||||
it can be executed in less than 10ms.
|
||||
|
||||
``?_ttl=SECONDS``
|
||||
For how many seconds should this response be cached by HTTP proxies? Use
|
||||
``?_ttl=0`` to disable HTTP caching entirely for this request.
|
||||
|
||||
Special table arguments
|
||||
-----------------------
|
||||
|
||||
|
@ -163,16 +190,6 @@ The Datasette table view takes a number of special querystring arguments:
|
|||
You can pass multiple ``_group_count`` columns to return counts against
|
||||
unique combinations of those columns.
|
||||
|
||||
``?_timelimit=MS``
|
||||
Sets a custom time limit for the query in ms. You can use this for optimistic
|
||||
queries where you would like Datasette to give up if the query takes too
|
||||
long, for example if you want to implement autocomplete search but only if
|
||||
it can be executed in less than 10ms.
|
||||
|
||||
``?_ttl=SECONDS``
|
||||
For how many seconds should this response be cached by HTTP proxies? Use
|
||||
``?_ttl=0`` to disable HTTP caching entirely for this request.
|
||||
|
||||
``?_next=TOKEN``
|
||||
Pagination by continuation token - pass the token that was returned in the
|
||||
``"next"`` property by the previous page.
|
||||
|
|
|
@ -1151,3 +1151,39 @@ def test_suggest_facets_off():
|
|||
def test_ttl_parameter(app_client, path, expected_cache_control):
|
||||
response = app_client.get(path, gather_request=False)
|
||||
assert expected_cache_control == response.headers['Cache-Control']
|
||||
|
||||
|
||||
test_json_columns_default_expected = [{
|
||||
"intval": 1,
|
||||
"strval": "s",
|
||||
"floatval": 0.5,
|
||||
"jsonval": "{\"foo\": \"bar\"}"
|
||||
}]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("extra_args,expected", [
|
||||
("", test_json_columns_default_expected),
|
||||
("&_json=intval", test_json_columns_default_expected),
|
||||
("&_json=strval", test_json_columns_default_expected),
|
||||
("&_json=floatval", test_json_columns_default_expected),
|
||||
("&_json=jsonval", [{
|
||||
"intval": 1,
|
||||
"strval": "s",
|
||||
"floatval": 0.5,
|
||||
"jsonval": {
|
||||
"foo": "bar"
|
||||
}
|
||||
}])
|
||||
])
|
||||
def test_json_columns(app_client, extra_args, expected):
|
||||
sql = '''
|
||||
select 1 as intval, "s" as strval, 0.5 as floatval,
|
||||
'{"foo": "bar"}' as jsonval
|
||||
'''
|
||||
path = "/test_tables.json?" + urllib.parse.urlencode({
|
||||
"sql": sql,
|
||||
"_shape": "array"
|
||||
})
|
||||
path += extra_args
|
||||
response = app_client.get(path, gather_request=False)
|
||||
assert expected == response.json
|
||||
|
|
Ładowanie…
Reference in New Issue