mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
New ?_shape=objects/object/lists param for JSON API (#192)
New _shape= parameter replacing old .jsono extension
Now instead of this:
/database/table.jsono
We use the _shape parameter like this:
/database/table.json?_shape=objects
Also introduced a new _shape called 'object' which looks like this:
/database/table.json?_shape=object
Returning an object for the rows key:
...
"rows": {
"pk1": {
...
},
"pk2": {
...
}
}
Refs #122
This commit is contained in:
parent
dd0566ff8e
commit
0abd3abacb
9 changed files with 244 additions and 23 deletions
|
|
@ -221,8 +221,20 @@ class BaseView(RenderMixin):
|
|||
if value:
|
||||
data[key] = value
|
||||
if as_json:
|
||||
# Special case for .jsono extension
|
||||
# Special case for .jsono extension - redirect to _shape=objects
|
||||
if as_json == '.jsono':
|
||||
return self.redirect(
|
||||
request,
|
||||
path_with_added_args(
|
||||
request,
|
||||
{'_shape': 'objects'},
|
||||
path=request.path.rsplit('.jsono', 1)[0] + '.json'
|
||||
),
|
||||
forward_querystring=False
|
||||
)
|
||||
# Deal with the _shape option
|
||||
shape = request.args.get('_shape', 'lists')
|
||||
if shape in ('objects', 'object'):
|
||||
columns = data.get('columns')
|
||||
rows = data.get('rows')
|
||||
if rows and columns:
|
||||
|
|
@ -230,6 +242,28 @@ class BaseView(RenderMixin):
|
|||
dict(zip(columns, row))
|
||||
for row in rows
|
||||
]
|
||||
if shape == 'object':
|
||||
error = None
|
||||
if 'primary_keys' not in data:
|
||||
error = '_shape=object is only available on tables'
|
||||
else:
|
||||
pks = data['primary_keys']
|
||||
if not pks:
|
||||
error = '_shape=object not available for tables with no primary keys'
|
||||
else:
|
||||
object_rows = {}
|
||||
for row in data['rows']:
|
||||
pk_string = path_from_row_pks(row, pks, not pks)
|
||||
object_rows[pk_string] = row
|
||||
data['rows'] = object_rows
|
||||
if error:
|
||||
data = {
|
||||
'ok': False,
|
||||
'error': error,
|
||||
'database': name,
|
||||
'database_hash': hash,
|
||||
}
|
||||
|
||||
headers = {}
|
||||
if self.ds.cors:
|
||||
headers['Access-Control-Allow-Origin'] = '*'
|
||||
|
|
@ -278,6 +312,8 @@ class BaseView(RenderMixin):
|
|||
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 = {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
</form>
|
||||
|
||||
{% if rows %}
|
||||
<p>This data as <a href="{{ url_json }}">.json</a>, <a href="{{ url_jsono }}">.jsono</a></p>
|
||||
<p>This data as <a href="{{ url_json }}">.json</a></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
{% block description_source_license %}{% include "_description_source_license.html" %}{% endblock %}
|
||||
|
||||
<p>This data as <a href="{{ url_json }}">.json</a>, <a href="{{ url_jsono }}">.jsono</a></p>
|
||||
<p>This data as <a href="{{ url_json }}">.json</a></p>
|
||||
|
||||
{% include custom_rows_and_columns_templates %}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@
|
|||
<p><a class="not-underlined" title="{{ query.sql }}" href="/{{ database }}-{{ database_hash }}?{{ {'sql': query.sql}|urlencode|safe }}{% if query.params %}&{{ query.params|urlencode|safe }}{% endif %}">✎ <span class="underlined">View and edit SQL</span></a></p>
|
||||
{% endif %}
|
||||
|
||||
<p>This data as <a href="{{ url_json }}">.json</a>, <a href="{{ url_jsono }}">.jsono</a></p>
|
||||
<p>This data as <a href="{{ url_json }}">.json</a></p>
|
||||
|
||||
{% include custom_rows_and_columns_templates %}
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,8 @@ def validate_sql_select(sql):
|
|||
raise InvalidSql(msg)
|
||||
|
||||
|
||||
def path_with_added_args(request, args):
|
||||
def path_with_added_args(request, args, path=None):
|
||||
path = path or request.path
|
||||
if isinstance(args, dict):
|
||||
args = args.items()
|
||||
arg_keys = set(a[0] for a in args)
|
||||
|
|
@ -151,7 +152,7 @@ def path_with_added_args(request, args):
|
|||
query_string = urllib.parse.urlencode(sorted(current))
|
||||
if query_string:
|
||||
query_string = '?{}'.format(query_string)
|
||||
return request.path + query_string
|
||||
return path + query_string
|
||||
|
||||
|
||||
def path_with_ext(request, ext):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue