mirror of
https://github.com/simonw/datasette.git
synced 2025-12-10 16:51:24 +01:00
parent
6a9fdcc071
commit
b46e370ee6
3 changed files with 32 additions and 6 deletions
33
app.py
33
app.py
|
|
@ -88,8 +88,11 @@ class BaseView(HTTPMethodView):
|
||||||
as_json = kwargs.pop('as_json')
|
as_json = kwargs.pop('as_json')
|
||||||
except KeyError:
|
except KeyError:
|
||||||
as_json = False
|
as_json = False
|
||||||
|
extra_template_data = {}
|
||||||
try:
|
try:
|
||||||
data = self.data(request, name, hash, **kwargs)
|
data, extra_template_data = self.data(
|
||||||
|
request, name, hash, **kwargs
|
||||||
|
)
|
||||||
except sqlite3.OperationalError as e:
|
except sqlite3.OperationalError as e:
|
||||||
data = {
|
data = {
|
||||||
'ok': False,
|
'ok': False,
|
||||||
|
|
@ -99,10 +102,15 @@ class BaseView(HTTPMethodView):
|
||||||
r = response.json(data)
|
r = response.json(data)
|
||||||
r.headers['Access-Control-Allow-Origin'] = '*'
|
r.headers['Access-Control-Allow-Origin'] = '*'
|
||||||
else:
|
else:
|
||||||
|
context = {**data, **dict(
|
||||||
|
extra_template_data()
|
||||||
|
if callable(extra_template_data)
|
||||||
|
else extra_template_data
|
||||||
|
)}
|
||||||
r = jinja.render(
|
r = jinja.render(
|
||||||
self.template,
|
self.template,
|
||||||
request,
|
request,
|
||||||
**data,
|
**context,
|
||||||
)
|
)
|
||||||
# Set far-future cache expiry
|
# Set far-future cache expiry
|
||||||
r.headers['Cache-Control'] = 'max-age={}'.format(
|
r.headers['Cache-Control'] = 'max-age={}'.format(
|
||||||
|
|
@ -136,9 +144,10 @@ class DatabaseView(BaseView):
|
||||||
columns = [r[0] for r in rows.description]
|
columns = [r[0] for r in rows.description]
|
||||||
return {
|
return {
|
||||||
'database': name,
|
'database': name,
|
||||||
'database_hash': hash,
|
|
||||||
'rows': rows,
|
'rows': rows,
|
||||||
'columns': columns,
|
'columns': columns,
|
||||||
|
}, {
|
||||||
|
'database_hash': hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -149,12 +158,16 @@ class TableView(BaseView):
|
||||||
conn = get_conn(name)
|
conn = get_conn(name)
|
||||||
rows = conn.execute('select * from {} limit 20'.format(table))
|
rows = conn.execute('select * from {} limit 20'.format(table))
|
||||||
columns = [r[0] for r in rows.description]
|
columns = [r[0] for r in rows.description]
|
||||||
|
pks = pks_for_table(conn, table)
|
||||||
return {
|
return {
|
||||||
'database': name,
|
'database': name,
|
||||||
'database_hash': hash,
|
|
||||||
'table': table,
|
'table': table,
|
||||||
'rows': rows,
|
'rows': rows,
|
||||||
'columns': columns,
|
'columns': columns,
|
||||||
|
'primary_keys': pks,
|
||||||
|
}, lambda: {
|
||||||
|
'database_hash': hash,
|
||||||
|
'row_link': lambda row: path_from_row_pks(row, pks),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -174,15 +187,19 @@ class RowView(BaseView):
|
||||||
)
|
)
|
||||||
rows = conn.execute(sql, pk_values)
|
rows = conn.execute(sql, pk_values)
|
||||||
columns = [r[0] for r in rows.description]
|
columns = [r[0] for r in rows.description]
|
||||||
|
pks = pks_for_table(conn, table)
|
||||||
rows = list(rows)
|
rows = list(rows)
|
||||||
if not rows:
|
if not rows:
|
||||||
raise NotFound('Record not found: {}'.format(pk_values))
|
raise NotFound('Record not found: {}'.format(pk_values))
|
||||||
return {
|
return {
|
||||||
'database': name,
|
'database': name,
|
||||||
'database_hash': hash,
|
|
||||||
'table': table,
|
'table': table,
|
||||||
'rows': rows,
|
'rows': rows,
|
||||||
'columns': columns,
|
'columns': columns,
|
||||||
|
'primary_keys': pks,
|
||||||
|
}, {
|
||||||
|
'database_hash': hash,
|
||||||
|
'row_link': None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -239,9 +256,13 @@ def pks_for_table(conn, table):
|
||||||
|
|
||||||
|
|
||||||
def path_from_row_pks(row, pks):
|
def path_from_row_pks(row, pks):
|
||||||
|
if not pks:
|
||||||
|
return ''
|
||||||
bits = []
|
bits = []
|
||||||
for pk in pks:
|
for pk in pks:
|
||||||
bits.append(urllib.parse.quote_plus(row[pk]))
|
bits.append(
|
||||||
|
urllib.parse.quote_plus(str(row[pk]))
|
||||||
|
)
|
||||||
return ','.join(bits)
|
return ','.join(bits)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,14 @@ td {
|
||||||
</style>
|
</style>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
|
{% if primary_keys and row_link %}<th scope="col">Link</th>{% endif %}
|
||||||
{% for column in columns %}<th scope="col">{{ column }}</th>{% endfor %}
|
{% for column in columns %}<th scope="col">{{ column }}</th>{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
{% for row in rows %}
|
{% for row in rows %}
|
||||||
<tr>
|
<tr>
|
||||||
|
{% if primary_keys and row_link %}
|
||||||
|
<td><a href="/{{ database }}-{{ database_hash }}/{{ table }}/{{ row_link(row) }}">{{ row_link(row) }}</a></td>
|
||||||
|
{% endif %}
|
||||||
{% for td in row %}
|
{% for td in row %}
|
||||||
<td>{{ td }}</td>
|
<td>{{ td }}</td>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ def test_pks_for_table(sql, table, expected_keys):
|
||||||
@pytest.mark.parametrize('row,pks,expected_path', [
|
@pytest.mark.parametrize('row,pks,expected_path', [
|
||||||
({'A': 'foo', 'B': 'bar'}, ['A', 'B'], 'foo,bar'),
|
({'A': 'foo', 'B': 'bar'}, ['A', 'B'], 'foo,bar'),
|
||||||
({'A': 'f,o', 'B': 'bar'}, ['A', 'B'], 'f%2Co,bar'),
|
({'A': 'f,o', 'B': 'bar'}, ['A', 'B'], 'f%2Co,bar'),
|
||||||
|
({'A': 123}, ['A'], '123'),
|
||||||
])
|
])
|
||||||
def test_path_from_row_pks(row, pks, expected_path):
|
def test_path_from_row_pks(row, pks, expected_path):
|
||||||
actual_path = app.path_from_row_pks(row, pks)
|
actual_path = app.path_from_row_pks(row, pks)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue