kopia lustrzana https://github.com/simonw/datasette
Applied sphinx-inline-tabs to remaining examples, refs #1153
rodzic
0183e1a72d
commit
c076fb65e0
|
@ -212,23 +212,63 @@ Access to an instance
|
||||||
|
|
||||||
Here's how to restrict access to your entire Datasette instance to just the ``"id": "root"`` user:
|
Here's how to restrict access to your entire Datasette instance to just the ``"id": "root"`` user:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
from metadata_doc import metadata_example
|
||||||
{
|
metadata_example(cog, {
|
||||||
"title": "My private Datasette instance",
|
"title": "My private Datasette instance",
|
||||||
"allow": {
|
"allow": {
|
||||||
"id": "root"
|
"id": "root"
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
title: My private Datasette instance
|
||||||
|
allow:
|
||||||
|
id: root
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "My private Datasette instance",
|
||||||
|
"allow": {
|
||||||
|
"id": "root"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
To deny access to all users, you can use ``"allow": false``:
|
To deny access to all users, you can use ``"allow": false``:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"title": "My entirely inaccessible instance",
|
"title": "My entirely inaccessible instance",
|
||||||
"allow": false
|
"allow": False
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
title: My entirely inaccessible instance
|
||||||
|
allow: false
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "My entirely inaccessible instance",
|
||||||
|
"allow": false
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
One reason to do this is if you are using a Datasette plugin - such as `datasette-permissions-sql <https://github.com/simonw/datasette-permissions-sql>`__ - to control permissions instead.
|
One reason to do this is if you are using a Datasette plugin - such as `datasette-permissions-sql <https://github.com/simonw/datasette-permissions-sql>`__ - to control permissions instead.
|
||||||
|
|
||||||
|
@ -239,9 +279,8 @@ Access to specific databases
|
||||||
|
|
||||||
To limit access to a specific ``private.db`` database to just authenticated users, use the ``"allow"`` block like this:
|
To limit access to a specific ``private.db`` database to just authenticated users, use the ``"allow"`` block like this:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"private": {
|
"private": {
|
||||||
"allow": {
|
"allow": {
|
||||||
|
@ -249,7 +288,33 @@ To limit access to a specific ``private.db`` database to just authenticated user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
private:
|
||||||
|
allow:
|
||||||
|
id: '*'
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"private": {
|
||||||
|
"allow": {
|
||||||
|
"id": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
.. _authentication_permissions_table:
|
.. _authentication_permissions_table:
|
||||||
|
|
||||||
|
@ -258,9 +323,8 @@ Access to specific tables and views
|
||||||
|
|
||||||
To limit access to the ``users`` table in your ``bakery.db`` database:
|
To limit access to the ``users`` table in your ``bakery.db`` database:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"bakery": {
|
"bakery": {
|
||||||
"tables": {
|
"tables": {
|
||||||
|
@ -272,7 +336,39 @@ To limit access to the ``users`` table in your ``bakery.db`` database:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
bakery:
|
||||||
|
tables:
|
||||||
|
users:
|
||||||
|
allow:
|
||||||
|
id: '*'
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"bakery": {
|
||||||
|
"tables": {
|
||||||
|
"users": {
|
||||||
|
"allow": {
|
||||||
|
"id": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
This works for SQL views as well - you can list their names in the ``"tables"`` block above in the same way as regular tables.
|
This works for SQL views as well - you can list their names in the ``"tables"`` block above in the same way as regular tables.
|
||||||
|
|
||||||
|
@ -290,15 +386,14 @@ Access to specific canned queries
|
||||||
|
|
||||||
To limit access to the ``add_name`` canned query in your ``dogs.db`` database to just the :ref:`root user<authentication_root>`:
|
To limit access to the ``add_name`` canned query in your ``dogs.db`` database to just the :ref:`root user<authentication_root>`:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"dogs": {
|
"dogs": {
|
||||||
"queries": {
|
"queries": {
|
||||||
"add_name": {
|
"add_name": {
|
||||||
"sql": "INSERT INTO names (name) VALUES (:name)",
|
"sql": "INSERT INTO names (name) VALUES (:name)",
|
||||||
"write": true,
|
"write": True,
|
||||||
"allow": {
|
"allow": {
|
||||||
"id": ["root"]
|
"id": ["root"]
|
||||||
}
|
}
|
||||||
|
@ -306,7 +401,46 @@ To limit access to the ``add_name`` canned query in your ``dogs.db`` database to
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
dogs:
|
||||||
|
queries:
|
||||||
|
add_name:
|
||||||
|
sql: INSERT INTO names (name) VALUES (:name)
|
||||||
|
write: true
|
||||||
|
allow:
|
||||||
|
id:
|
||||||
|
- root
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"dogs": {
|
||||||
|
"queries": {
|
||||||
|
"add_name": {
|
||||||
|
"sql": "INSERT INTO names (name) VALUES (:name)",
|
||||||
|
"write": true,
|
||||||
|
"allow": {
|
||||||
|
"id": [
|
||||||
|
"root"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
.. _authentication_permissions_execute_sql:
|
.. _authentication_permissions_execute_sql:
|
||||||
|
|
||||||
|
@ -323,27 +457,61 @@ You can alternatively use an ``"allow_sql"`` block to control who is allowed to
|
||||||
|
|
||||||
To prevent any user from executing arbitrary SQL queries, use this:
|
To prevent any user from executing arbitrary SQL queries, use this:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
|
"allow_sql": False
|
||||||
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
{
|
.. tab:: YAML
|
||||||
"allow_sql": false
|
|
||||||
}
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
allow_sql: false
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"allow_sql": false
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
To enable just the :ref:`root user<authentication_root>` to execute SQL for all databases in your instance, use the following:
|
To enable just the :ref:`root user<authentication_root>` to execute SQL for all databases in your instance, use the following:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"allow_sql": {
|
"allow_sql": {
|
||||||
"id": "root"
|
"id": "root"
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
allow_sql:
|
||||||
|
id: root
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"allow_sql": {
|
||||||
|
"id": "root"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
To limit this ability for just one specific database, use this:
|
To limit this ability for just one specific database, use this:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"mydatabase": {
|
"mydatabase": {
|
||||||
"allow_sql": {
|
"allow_sql": {
|
||||||
|
@ -351,7 +519,33 @@ To limit this ability for just one specific database, use this:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
mydatabase:
|
||||||
|
allow_sql:
|
||||||
|
id: root
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"mydatabase": {
|
||||||
|
"allow_sql": {
|
||||||
|
"id": "root"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
.. _authentication_permissions_other:
|
.. _authentication_permissions_other:
|
||||||
|
|
||||||
|
@ -362,21 +556,42 @@ For all other permissions, you can use one or more ``"permissions"`` blocks in y
|
||||||
|
|
||||||
To grant access to the :ref:`permissions debug tool <PermissionsDebugView>` to all signed in users you can grant ``permissions-debug`` to any actor with an ``id`` matching the wildcard ``*`` by adding this a the root of your metadata:
|
To grant access to the :ref:`permissions debug tool <PermissionsDebugView>` to all signed in users you can grant ``permissions-debug`` to any actor with an ``id`` matching the wildcard ``*`` by adding this a the root of your metadata:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"permissions": {
|
"permissions": {
|
||||||
"debug-menu": {
|
"debug-menu": {
|
||||||
"id": "*"
|
"id": "*"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
debug-menu:
|
||||||
|
id: '*'
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"debug-menu": {
|
||||||
|
"id": "*"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
To grant ``create-table`` to the user with ``id`` of ``editor`` for the ``docs`` database:
|
To grant ``create-table`` to the user with ``id`` of ``editor`` for the ``docs`` database:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"docs": {
|
"docs": {
|
||||||
"permissions": {
|
"permissions": {
|
||||||
|
@ -386,13 +601,41 @@ To grant ``create-table`` to the user with ``id`` of ``editor`` for the ``docs``
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
docs:
|
||||||
|
permissions:
|
||||||
|
create-table:
|
||||||
|
id: editor
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"docs": {
|
||||||
|
"permissions": {
|
||||||
|
"create-table": {
|
||||||
|
"id": "editor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
And for ``insert-row`` against the ``reports`` table in that ``docs`` database:
|
And for ``insert-row`` against the ``reports`` table in that ``docs`` database:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"docs": {
|
"docs": {
|
||||||
"tables": {
|
"tables": {
|
||||||
|
@ -406,7 +649,42 @@ And for ``insert-row`` against the ``reports`` table in that ``docs`` database:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
docs:
|
||||||
|
tables:
|
||||||
|
reports:
|
||||||
|
permissions:
|
||||||
|
insert-row:
|
||||||
|
id: editor
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"docs": {
|
||||||
|
"tables": {
|
||||||
|
"reports": {
|
||||||
|
"permissions": {
|
||||||
|
"insert-row": {
|
||||||
|
"id": "editor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
The :ref:`permissions debug tool <PermissionsDebugView>` can be useful for helping test permissions that you have configured in this way.
|
The :ref:`permissions debug tool <PermissionsDebugView>` can be useful for helping test permissions that you have configured in this way.
|
||||||
|
|
||||||
|
|
|
@ -12,20 +12,45 @@ Custom CSS and JavaScript
|
||||||
|
|
||||||
When you launch Datasette, you can specify a custom metadata file like this::
|
When you launch Datasette, you can specify a custom metadata file like this::
|
||||||
|
|
||||||
datasette mydb.db --metadata metadata.json
|
datasette mydb.db --metadata metadata.yaml
|
||||||
|
|
||||||
Your ``metadata.json`` file can include links that look like this:
|
Your ``metadata.yaml`` file can include links that look like this:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
from metadata_doc import metadata_example
|
||||||
{
|
metadata_example(cog, {
|
||||||
"extra_css_urls": [
|
"extra_css_urls": [
|
||||||
"https://simonwillison.net/static/css/all.bf8cd891642c.css"
|
"https://simonwillison.net/static/css/all.bf8cd891642c.css"
|
||||||
],
|
],
|
||||||
"extra_js_urls": [
|
"extra_js_urls": [
|
||||||
"https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
"https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||||
]
|
]
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
extra_css_urls:
|
||||||
|
- https://simonwillison.net/static/css/all.bf8cd891642c.css
|
||||||
|
extra_js_urls:
|
||||||
|
- https://code.jquery.com/jquery-3.2.1.slim.min.js
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"extra_css_urls": [
|
||||||
|
"https://simonwillison.net/static/css/all.bf8cd891642c.css"
|
||||||
|
],
|
||||||
|
"extra_js_urls": [
|
||||||
|
"https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
The extra CSS and JavaScript files will be linked in the ``<head>`` of every page:
|
The extra CSS and JavaScript files will be linked in the ``<head>`` of every page:
|
||||||
|
|
||||||
|
@ -36,9 +61,8 @@ The extra CSS and JavaScript files will be linked in the ``<head>`` of every pag
|
||||||
|
|
||||||
You can also specify a SRI (subresource integrity hash) for these assets:
|
You can also specify a SRI (subresource integrity hash) for these assets:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"extra_css_urls": [
|
"extra_css_urls": [
|
||||||
{
|
{
|
||||||
"url": "https://simonwillison.net/static/css/all.bf8cd891642c.css",
|
"url": "https://simonwillison.net/static/css/all.bf8cd891642c.css",
|
||||||
|
@ -51,7 +75,40 @@ You can also specify a SRI (subresource integrity hash) for these assets:
|
||||||
"sri": "sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
|
"sri": "sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
extra_css_urls:
|
||||||
|
- url: https://simonwillison.net/static/css/all.bf8cd891642c.css
|
||||||
|
sri: sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI
|
||||||
|
extra_js_urls:
|
||||||
|
- url: https://code.jquery.com/jquery-3.2.1.slim.min.js
|
||||||
|
sri: sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g=
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"extra_css_urls": [
|
||||||
|
{
|
||||||
|
"url": "https://simonwillison.net/static/css/all.bf8cd891642c.css",
|
||||||
|
"sri": "sha384-9qIZekWUyjCyDIf2YK1FRoKiPJq4PHt6tp/ulnuuyRBvazd0hG7pWbE99zvwSznI"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"extra_js_urls": [
|
||||||
|
{
|
||||||
|
"url": "https://code.jquery.com/jquery-3.2.1.slim.min.js",
|
||||||
|
"sri": "sha256-k2WSCIexGzOj3Euiig+TlR8gA0EmPjuc79OEeY5L45g="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
This will produce:
|
This will produce:
|
||||||
|
|
||||||
|
@ -69,16 +126,39 @@ matches the content served. You can generate hashes using `www.srihash.org <http
|
||||||
|
|
||||||
Items in ``"extra_js_urls"`` can specify ``"module": true`` if they reference JavaScript that uses `JavaScript modules <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules>`__. This configuration:
|
Items in ``"extra_js_urls"`` can specify ``"module": true`` if they reference JavaScript that uses `JavaScript modules <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules>`__. This configuration:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"extra_js_urls": [
|
"extra_js_urls": [
|
||||||
{
|
{
|
||||||
"url": "https://example.datasette.io/module.js",
|
"url": "https://example.datasette.io/module.js",
|
||||||
"module": true
|
"module": True
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
extra_js_urls:
|
||||||
|
- url: https://example.datasette.io/module.js
|
||||||
|
module: true
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"extra_js_urls": [
|
||||||
|
{
|
||||||
|
"url": "https://example.datasette.io/module.js",
|
||||||
|
"module": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
Will produce this HTML:
|
Will produce this HTML:
|
||||||
|
|
||||||
|
@ -188,16 +268,40 @@ The following URLs will now serve the content from those CSS and JS files::
|
||||||
|
|
||||||
You can reference those files from ``metadata.json`` like so:
|
You can reference those files from ``metadata.json`` like so:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"extra_css_urls": [
|
"extra_css_urls": [
|
||||||
"/assets/styles.css"
|
"/assets/styles.css"
|
||||||
],
|
],
|
||||||
"extra_js_urls": [
|
"extra_js_urls": [
|
||||||
"/assets/app.js"
|
"/assets/app.js"
|
||||||
]
|
]
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
extra_css_urls:
|
||||||
|
- /assets/styles.css
|
||||||
|
extra_js_urls:
|
||||||
|
- /assets/app.js
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"extra_css_urls": [
|
||||||
|
"/assets/styles.css"
|
||||||
|
],
|
||||||
|
"extra_js_urls": [
|
||||||
|
"/assets/app.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
Publishing static assets
|
Publishing static assets
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
124
docs/facets.rst
124
docs/facets.rst
|
@ -98,16 +98,16 @@ You can increase this on an individual page by adding ``?_facet_size=100`` to th
|
||||||
|
|
||||||
.. _facets_metadata:
|
.. _facets_metadata:
|
||||||
|
|
||||||
Facets in metadata.json
|
Facets in metadata
|
||||||
-----------------------
|
------------------
|
||||||
|
|
||||||
You can turn facets on by default for specific tables by adding them to a ``"facets"`` key in a Datasette :ref:`metadata` file.
|
You can turn facets on by default for specific tables by adding them to a ``"facets"`` key in a Datasette :ref:`metadata` file.
|
||||||
|
|
||||||
Here's an example that turns on faceting by default for the ``qLegalStatus`` column in the ``Street_Tree_List`` table in the ``sf-trees`` database:
|
Here's an example that turns on faceting by default for the ``qLegalStatus`` column in the ``Street_Tree_List`` table in the ``sf-trees`` database:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
from metadata_doc import metadata_example
|
||||||
{
|
metadata_example(cog, {
|
||||||
"databases": {
|
"databases": {
|
||||||
"sf-trees": {
|
"sf-trees": {
|
||||||
"tables": {
|
"tables": {
|
||||||
|
@ -117,26 +117,82 @@ Here's an example that turns on faceting by default for the ``qLegalStatus`` col
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
sf-trees:
|
||||||
|
tables:
|
||||||
|
Street_Tree_List:
|
||||||
|
facets:
|
||||||
|
- qLegalStatus
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"sf-trees": {
|
||||||
|
"tables": {
|
||||||
|
"Street_Tree_List": {
|
||||||
|
"facets": [
|
||||||
|
"qLegalStatus"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
Facets defined in this way will always be shown in the interface and returned in the API, regardless of the ``_facet`` arguments passed to the view.
|
Facets defined in this way will always be shown in the interface and returned in the API, regardless of the ``_facet`` arguments passed to the view.
|
||||||
|
|
||||||
You can specify :ref:`array <facet_by_json_array>` or :ref:`date <facet_by_date>` facets in metadata using JSON objects with a single key of ``array`` or ``date`` and a value specifying the column, like this:
|
You can specify :ref:`array <facet_by_json_array>` or :ref:`date <facet_by_date>` facets in metadata using JSON objects with a single key of ``array`` or ``date`` and a value specifying the column, like this:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
|
"facets": [
|
||||||
|
{"array": "tags"},
|
||||||
|
{"date": "created"}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
{
|
.. tab:: YAML
|
||||||
"facets": [
|
|
||||||
{"array": "tags"},
|
.. code-block:: yaml
|
||||||
{"date": "created"}
|
|
||||||
]
|
facets:
|
||||||
}
|
- array: tags
|
||||||
|
- date: created
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"facets": [
|
||||||
|
{
|
||||||
|
"array": "tags"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"date": "created"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
You can change the default facet size (the number of results shown for each facet) for a table using ``facet_size``:
|
You can change the default facet size (the number of results shown for each facet) for a table using ``facet_size``:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"sf-trees": {
|
"sf-trees": {
|
||||||
"tables": {
|
"tables": {
|
||||||
|
@ -147,7 +203,41 @@ You can change the default facet size (the number of results shown for each face
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
sf-trees:
|
||||||
|
tables:
|
||||||
|
Street_Tree_List:
|
||||||
|
facets:
|
||||||
|
- qLegalStatus
|
||||||
|
facet_size: 10
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"sf-trees": {
|
||||||
|
"tables": {
|
||||||
|
"Street_Tree_List": {
|
||||||
|
"facets": [
|
||||||
|
"qLegalStatus"
|
||||||
|
],
|
||||||
|
"facet_size": 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
Suggested facets
|
Suggested facets
|
||||||
----------------
|
----------------
|
||||||
|
|
|
@ -64,9 +64,9 @@ The ``"searchmode": "raw"`` property can be used to default the table to accepti
|
||||||
|
|
||||||
Here is an example which enables full-text search (with SQLite advanced search operators) for a ``display_ads`` view which is defined against the ``ads`` table and hence needs to run FTS against the ``ads_fts`` table, using the ``id`` as the primary key:
|
Here is an example which enables full-text search (with SQLite advanced search operators) for a ``display_ads`` view which is defined against the ``ads`` table and hence needs to run FTS against the ``ads_fts`` table, using the ``id`` as the primary key:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
from metadata_doc import metadata_example
|
||||||
{
|
metadata_example(cog, {
|
||||||
"databases": {
|
"databases": {
|
||||||
"russian-ads": {
|
"russian-ads": {
|
||||||
"tables": {
|
"tables": {
|
||||||
|
@ -78,7 +78,40 @@ Here is an example which enables full-text search (with SQLite advanced search o
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
russian-ads:
|
||||||
|
tables:
|
||||||
|
display_ads:
|
||||||
|
fts_table: ads_fts
|
||||||
|
fts_pk: id
|
||||||
|
searchmode: raw
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"russian-ads": {
|
||||||
|
"tables": {
|
||||||
|
"display_ads": {
|
||||||
|
"fts_table": "ads_fts",
|
||||||
|
"fts_pk": "id",
|
||||||
|
"searchmode": "raw"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
.. _full_text_search_custom_sql:
|
.. _full_text_search_custom_sql:
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,25 @@
|
||||||
import json
|
import json
|
||||||
import textwrap
|
import textwrap
|
||||||
import yaml
|
from yaml import safe_dump
|
||||||
|
from ruamel.yaml import round_trip_load
|
||||||
|
|
||||||
|
|
||||||
def metadata_example(cog, example):
|
def metadata_example(cog, data=None, yaml=None):
|
||||||
|
assert data or yaml, "Must provide data= or yaml="
|
||||||
|
assert not (data and yaml), "Cannot use data= and yaml="
|
||||||
|
output_yaml = None
|
||||||
|
if yaml:
|
||||||
|
# dedent it first
|
||||||
|
yaml = textwrap.dedent(yaml).strip()
|
||||||
|
# round_trip_load to preserve key order:
|
||||||
|
data = round_trip_load(yaml)
|
||||||
|
output_yaml = yaml
|
||||||
|
else:
|
||||||
|
output_yaml = safe_dump(data, sort_keys=False)
|
||||||
cog.out("\n.. tab:: YAML\n\n")
|
cog.out("\n.. tab:: YAML\n\n")
|
||||||
cog.out(" .. code-block:: yaml\n\n")
|
cog.out(" .. code-block:: yaml\n\n")
|
||||||
cog.out(textwrap.indent(yaml.safe_dump(example, sort_keys=False), " "))
|
cog.out(textwrap.indent(output_yaml, " "))
|
||||||
cog.out("\n\n.. tab:: JSON\n\n")
|
cog.out("\n\n.. tab:: JSON\n\n")
|
||||||
cog.out(" .. code-block:: json\n\n")
|
cog.out(" .. code-block:: json\n\n")
|
||||||
cog.out(textwrap.indent(json.dumps(example, indent=2), " "))
|
cog.out(textwrap.indent(json.dumps(data, indent=2), " "))
|
||||||
cog.out("\n")
|
cog.out("\n")
|
||||||
|
|
153
docs/plugins.rst
153
docs/plugins.rst
|
@ -245,9 +245,9 @@ Plugins can have their own configuration, embedded in a :ref:`metadata` file. Co
|
||||||
|
|
||||||
Here is an example of some plugin configuration for a specific table:
|
Here is an example of some plugin configuration for a specific table:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
from metadata_doc import metadata_example
|
||||||
{
|
metadata_example(cog, {
|
||||||
"databases": {
|
"databases": {
|
||||||
"sf-trees": {
|
"sf-trees": {
|
||||||
"tables": {
|
"tables": {
|
||||||
|
@ -262,7 +262,44 @@ Here is an example of some plugin configuration for a specific table:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
sf-trees:
|
||||||
|
tables:
|
||||||
|
Street_Tree_List:
|
||||||
|
plugins:
|
||||||
|
datasette-cluster-map:
|
||||||
|
latitude_column: lat
|
||||||
|
longitude_column: lng
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"sf-trees": {
|
||||||
|
"tables": {
|
||||||
|
"Street_Tree_List": {
|
||||||
|
"plugins": {
|
||||||
|
"datasette-cluster-map": {
|
||||||
|
"latitude_column": "lat",
|
||||||
|
"longitude_column": "lng"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
This tells the ``datasette-cluster-map`` column which latitude and longitude columns should be used for a table called ``Street_Tree_List`` inside a database file called ``sf-trees.db``.
|
This tells the ``datasette-cluster-map`` column which latitude and longitude columns should be used for a table called ``Street_Tree_List`` inside a database file called ``sf-trees.db``.
|
||||||
|
|
||||||
|
@ -271,13 +308,12 @@ This tells the ``datasette-cluster-map`` column which latitude and longitude col
|
||||||
Secret configuration values
|
Secret configuration values
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Any values embedded in ``metadata.json`` will be visible to anyone who views the ``/-/metadata`` page of your Datasette instance. Some plugins may need configuration that should stay secret - API keys for example. There are two ways in which you can store secret configuration values.
|
Any values embedded in ``metadata.yaml`` will be visible to anyone who views the ``/-/metadata`` page of your Datasette instance. Some plugins may need configuration that should stay secret - API keys for example. There are two ways in which you can store secret configuration values.
|
||||||
|
|
||||||
**As environment variables**. If your secret lives in an environment variable that is available to the Datasette process, you can indicate that the configuration value should be read from that environment variable like so:
|
**As environment variables**. If your secret lives in an environment variable that is available to the Datasette process, you can indicate that the configuration value should be read from that environment variable like so:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"datasette-auth-github": {
|
"datasette-auth-github": {
|
||||||
"client_secret": {
|
"client_secret": {
|
||||||
|
@ -285,13 +321,38 @@ Any values embedded in ``metadata.json`` will be visible to anyone who views the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
datasette-auth-github:
|
||||||
|
client_secret:
|
||||||
|
$env: GITHUB_CLIENT_SECRET
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"datasette-auth-github": {
|
||||||
|
"client_secret": {
|
||||||
|
"$env": "GITHUB_CLIENT_SECRET"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
**As values in separate files**. Your secrets can also live in files on disk. To specify a secret should be read from a file, provide the full file path like this:
|
**As values in separate files**. Your secrets can also live in files on disk. To specify a secret should be read from a file, provide the full file path like this:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"datasette-auth-github": {
|
"datasette-auth-github": {
|
||||||
"client_secret": {
|
"client_secret": {
|
||||||
|
@ -299,7 +360,33 @@ Any values embedded in ``metadata.json`` will be visible to anyone who views the
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
datasette-auth-github:
|
||||||
|
client_secret:
|
||||||
|
$file: /secrets/client-secret
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"datasette-auth-github": {
|
||||||
|
"client_secret": {
|
||||||
|
"$file": "/secrets/client-secret"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
If you are publishing your data using the :ref:`datasette publish <cli_publish>` family of commands, you can use the ``--plugin-secret`` option to set these secrets at publish time. For example, using Heroku you might run the following command::
|
If you are publishing your data using the :ref:`datasette publish <cli_publish>` family of commands, you can use the ``--plugin-secret`` option to set these secrets at publish time. For example, using Heroku you might run the following command::
|
||||||
|
|
||||||
|
@ -309,11 +396,10 @@ If you are publishing your data using the :ref:`datasette publish <cli_publish>`
|
||||||
--plugin-secret datasette-auth-github client_id your_client_id \
|
--plugin-secret datasette-auth-github client_id your_client_id \
|
||||||
--plugin-secret datasette-auth-github client_secret your_client_secret
|
--plugin-secret datasette-auth-github client_secret your_client_secret
|
||||||
|
|
||||||
This will set the necessary environment variables and add the following to the deployed ``metadata.json``:
|
This will set the necessary environment variables and add the following to the deployed ``metadata.yaml``:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"datasette-auth-github": {
|
"datasette-auth-github": {
|
||||||
"client_id": {
|
"client_id": {
|
||||||
|
@ -324,4 +410,35 @@ This will set the necessary environment variables and add the following to the d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
plugins:
|
||||||
|
datasette-auth-github:
|
||||||
|
client_id:
|
||||||
|
$env: DATASETTE_AUTH_GITHUB_CLIENT_ID
|
||||||
|
client_secret:
|
||||||
|
$env: DATASETTE_AUTH_GITHUB_CLIENT_SECRET
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"datasette-auth-github": {
|
||||||
|
"client_id": {
|
||||||
|
"$env": "DATASETTE_AUTH_GITHUB_CLIENT_ID"
|
||||||
|
},
|
||||||
|
"client_secret": {
|
||||||
|
"$env": "DATASETTE_AUTH_GITHUB_CLIENT_SECRET"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
|
@ -64,11 +64,11 @@ The quickest way to create views is with the SQLite command-line interface::
|
||||||
Canned queries
|
Canned queries
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
As an alternative to adding views to your database, you can define canned queries inside your ``metadata.json`` file. Here's an example:
|
As an alternative to adding views to your database, you can define canned queries inside your ``metadata.yaml`` file. Here's an example:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
from metadata_doc import metadata_example
|
||||||
{
|
metadata_example(cog, {
|
||||||
"databases": {
|
"databases": {
|
||||||
"sf-trees": {
|
"sf-trees": {
|
||||||
"queries": {
|
"queries": {
|
||||||
|
@ -78,7 +78,36 @@ As an alternative to adding views to your database, you can define canned querie
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
sf-trees:
|
||||||
|
queries:
|
||||||
|
just_species:
|
||||||
|
sql: select qSpecies from Street_Tree_List
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"sf-trees": {
|
||||||
|
"queries": {
|
||||||
|
"just_species": {
|
||||||
|
"sql": "select qSpecies from Street_Tree_List"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
Then run Datasette like this::
|
Then run Datasette like this::
|
||||||
|
|
||||||
|
@ -111,38 +140,58 @@ Here's an example of a canned query with a named parameter:
|
||||||
where neighborhood like '%' || :text || '%'
|
where neighborhood like '%' || :text || '%'
|
||||||
order by neighborhood;
|
order by neighborhood;
|
||||||
|
|
||||||
In the canned query metadata (here :ref:`metadata_yaml` as ``metadata.yaml``) it looks like this:
|
In the canned query metadata looks like this:
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
|
.. [[[cog
|
||||||
|
metadata_example(cog, yaml="""
|
||||||
databases:
|
databases:
|
||||||
fixtures:
|
fixtures:
|
||||||
queries:
|
queries:
|
||||||
neighborhood_search:
|
neighborhood_search:
|
||||||
|
title: Search neighborhoods
|
||||||
sql: |-
|
sql: |-
|
||||||
select neighborhood, facet_cities.name, state
|
select neighborhood, facet_cities.name, state
|
||||||
from facetable
|
from facetable
|
||||||
join facet_cities on facetable.city_id = facet_cities.id
|
join facet_cities on facetable.city_id = facet_cities.id
|
||||||
where neighborhood like '%' || :text || '%'
|
where neighborhood like '%' || :text || '%'
|
||||||
order by neighborhood
|
order by neighborhood
|
||||||
title: Search neighborhoods
|
""")
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
Here's the equivalent using JSON (as ``metadata.json``):
|
.. tab:: YAML
|
||||||
|
|
||||||
.. code-block:: json
|
.. code-block:: yaml
|
||||||
|
|
||||||
{
|
databases:
|
||||||
"databases": {
|
fixtures:
|
||||||
|
queries:
|
||||||
|
neighborhood_search:
|
||||||
|
title: Search neighborhoods
|
||||||
|
sql: |-
|
||||||
|
select neighborhood, facet_cities.name, state
|
||||||
|
from facetable
|
||||||
|
join facet_cities on facetable.city_id = facet_cities.id
|
||||||
|
where neighborhood like '%' || :text || '%'
|
||||||
|
order by neighborhood
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
"fixtures": {
|
"fixtures": {
|
||||||
"queries": {
|
"queries": {
|
||||||
"neighborhood_search": {
|
"neighborhood_search": {
|
||||||
"sql": "select neighborhood, facet_cities.name, state\nfrom facetable\n join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%'\norder by neighborhood",
|
"title": "Search neighborhoods",
|
||||||
"title": "Search neighborhoods"
|
"sql": "select neighborhood, facet_cities.name, state\nfrom facetable\n join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%'\norder by neighborhood"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.. [[[end]]]
|
||||||
|
|
||||||
Note that we are using SQLite string concatenation here - the ``||`` operator - to add wildcard ``%`` characters to the string provided by the user.
|
Note that we are using SQLite string concatenation here - the ``||`` operator - to add wildcard ``%`` characters to the string provided by the user.
|
||||||
|
|
||||||
|
@ -153,12 +202,13 @@ In this example the ``:text`` named parameter is automatically extracted from th
|
||||||
|
|
||||||
You can alternatively provide an explicit list of named parameters using the ``"params"`` key, like this:
|
You can alternatively provide an explicit list of named parameters using the ``"params"`` key, like this:
|
||||||
|
|
||||||
.. code-block:: yaml
|
.. [[[cog
|
||||||
|
metadata_example(cog, yaml="""
|
||||||
databases:
|
databases:
|
||||||
fixtures:
|
fixtures:
|
||||||
queries:
|
queries:
|
||||||
neighborhood_search:
|
neighborhood_search:
|
||||||
|
title: Search neighborhoods
|
||||||
params:
|
params:
|
||||||
- text
|
- text
|
||||||
sql: |-
|
sql: |-
|
||||||
|
@ -167,7 +217,47 @@ You can alternatively provide an explicit list of named parameters using the ``"
|
||||||
join facet_cities on facetable.city_id = facet_cities.id
|
join facet_cities on facetable.city_id = facet_cities.id
|
||||||
where neighborhood like '%' || :text || '%'
|
where neighborhood like '%' || :text || '%'
|
||||||
order by neighborhood
|
order by neighborhood
|
||||||
title: Search neighborhoods
|
""")
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
fixtures:
|
||||||
|
queries:
|
||||||
|
neighborhood_search:
|
||||||
|
title: Search neighborhoods
|
||||||
|
params:
|
||||||
|
- text
|
||||||
|
sql: |-
|
||||||
|
select neighborhood, facet_cities.name, state
|
||||||
|
from facetable
|
||||||
|
join facet_cities on facetable.city_id = facet_cities.id
|
||||||
|
where neighborhood like '%' || :text || '%'
|
||||||
|
order by neighborhood
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"fixtures": {
|
||||||
|
"queries": {
|
||||||
|
"neighborhood_search": {
|
||||||
|
"title": "Search neighborhoods",
|
||||||
|
"params": [
|
||||||
|
"text"
|
||||||
|
],
|
||||||
|
"sql": "select neighborhood, facet_cities.name, state\nfrom facetable\n join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%'\norder by neighborhood"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
.. _canned_queries_options:
|
.. _canned_queries_options:
|
||||||
|
|
||||||
|
@ -192,21 +282,54 @@ You can set a default fragment hash that will be included in the link to the can
|
||||||
|
|
||||||
This example demonstrates both ``fragment`` and ``hide_sql``:
|
This example demonstrates both ``fragment`` and ``hide_sql``:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, yaml="""
|
||||||
|
databases:
|
||||||
|
fixtures:
|
||||||
|
queries:
|
||||||
|
neighborhood_search:
|
||||||
|
fragment: fragment-goes-here
|
||||||
|
hide_sql: true
|
||||||
|
sql: |-
|
||||||
|
select neighborhood, facet_cities.name, state
|
||||||
|
from facetable join facet_cities on facetable.city_id = facet_cities.id
|
||||||
|
where neighborhood like '%' || :text || '%' order by neighborhood;
|
||||||
|
""")
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
{
|
.. tab:: YAML
|
||||||
"databases": {
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
fixtures:
|
||||||
|
queries:
|
||||||
|
neighborhood_search:
|
||||||
|
fragment: fragment-goes-here
|
||||||
|
hide_sql: true
|
||||||
|
sql: |-
|
||||||
|
select neighborhood, facet_cities.name, state
|
||||||
|
from facetable join facet_cities on facetable.city_id = facet_cities.id
|
||||||
|
where neighborhood like '%' || :text || '%' order by neighborhood;
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
"fixtures": {
|
"fixtures": {
|
||||||
"queries": {
|
"queries": {
|
||||||
"neighborhood_search": {
|
"neighborhood_search": {
|
||||||
"sql": "select neighborhood, facet_cities.name, state\nfrom facetable join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%' order by neighborhood;",
|
"fragment": "fragment-goes-here",
|
||||||
"fragment": "fragment-goes-here",
|
"hide_sql": true,
|
||||||
"hide_sql": true
|
"sql": "select neighborhood, facet_cities.name, state\nfrom facetable join facet_cities on facetable.city_id = facet_cities.id\nwhere neighborhood like '%' || :text || '%' order by neighborhood;"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.. [[[end]]]
|
||||||
|
|
||||||
`See here <https://latest.datasette.io/fixtures#queries>`__ for a demo of this in action.
|
`See here <https://latest.datasette.io/fixtures#queries>`__ for a demo of this in action.
|
||||||
|
|
||||||
|
@ -219,20 +342,50 @@ Canned queries by default are read-only. You can use the ``"write": true`` key t
|
||||||
|
|
||||||
See :ref:`authentication_permissions_query` for details on how to add permission checks to canned queries, using the ``"allow"`` key.
|
See :ref:`authentication_permissions_query` for details on how to add permission checks to canned queries, using the ``"allow"`` key.
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"mydatabase": {
|
"mydatabase": {
|
||||||
"queries": {
|
"queries": {
|
||||||
"add_name": {
|
"add_name": {
|
||||||
"sql": "INSERT INTO names (name) VALUES (:name)",
|
"sql": "INSERT INTO names (name) VALUES (:name)",
|
||||||
"write": true
|
"write": True
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
mydatabase:
|
||||||
|
queries:
|
||||||
|
add_name:
|
||||||
|
sql: INSERT INTO names (name) VALUES (:name)
|
||||||
|
write: true
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"mydatabase": {
|
||||||
|
"queries": {
|
||||||
|
"add_name": {
|
||||||
|
"sql": "INSERT INTO names (name) VALUES (:name)",
|
||||||
|
"write": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
This configuration will create a page at ``/mydatabase/add_name`` displaying a form with a ``name`` field. Submitting that form will execute the configured ``INSERT`` query.
|
This configuration will create a page at ``/mydatabase/add_name`` displaying a form with a ``name`` field. Submitting that form will execute the configured ``INSERT`` query.
|
||||||
|
|
||||||
|
@ -245,15 +398,14 @@ You can customize how Datasette represents success and errors using the followin
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
.. code-block:: json
|
.. [[[cog
|
||||||
|
metadata_example(cog, {
|
||||||
{
|
|
||||||
"databases": {
|
"databases": {
|
||||||
"mydatabase": {
|
"mydatabase": {
|
||||||
"queries": {
|
"queries": {
|
||||||
"add_name": {
|
"add_name": {
|
||||||
"sql": "INSERT INTO names (name) VALUES (:name)",
|
"sql": "INSERT INTO names (name) VALUES (:name)",
|
||||||
"write": true,
|
"write": True,
|
||||||
"on_success_message": "Name inserted",
|
"on_success_message": "Name inserted",
|
||||||
"on_success_redirect": "/mydatabase/names",
|
"on_success_redirect": "/mydatabase/names",
|
||||||
"on_error_message": "Name insert failed",
|
"on_error_message": "Name insert failed",
|
||||||
|
@ -262,7 +414,46 @@ For example:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
mydatabase:
|
||||||
|
queries:
|
||||||
|
add_name:
|
||||||
|
sql: INSERT INTO names (name) VALUES (:name)
|
||||||
|
write: true
|
||||||
|
on_success_message: Name inserted
|
||||||
|
on_success_redirect: /mydatabase/names
|
||||||
|
on_error_message: Name insert failed
|
||||||
|
on_error_redirect: /mydatabase
|
||||||
|
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"mydatabase": {
|
||||||
|
"queries": {
|
||||||
|
"add_name": {
|
||||||
|
"sql": "INSERT INTO names (name) VALUES (:name)",
|
||||||
|
"write": true,
|
||||||
|
"on_success_message": "Name inserted",
|
||||||
|
"on_success_redirect": "/mydatabase/names",
|
||||||
|
"on_error_message": "Name insert failed",
|
||||||
|
"on_error_redirect": "/mydatabase"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
You can use ``"params"`` to explicitly list the named parameters that should be displayed as form fields - otherwise they will be automatically detected.
|
You can use ``"params"`` to explicitly list the named parameters that should be displayed as form fields - otherwise they will be automatically detected.
|
||||||
|
|
||||||
|
@ -300,10 +491,10 @@ Available magic parameters are:
|
||||||
``_random_chars_*`` - e.g. ``_random_chars_128``
|
``_random_chars_*`` - e.g. ``_random_chars_128``
|
||||||
A random string of characters of the specified length.
|
A random string of characters of the specified length.
|
||||||
|
|
||||||
Here's an example configuration (this time using ``metadata.yaml`` since that provides better support for multi-line SQL queries) that adds a message from the authenticated user, storing various pieces of additional metadata using magic parameters:
|
Here's an example configuration that adds a message from the authenticated user, storing various pieces of additional metadata using magic parameters:
|
||||||
|
|
||||||
.. code-block:: yaml
|
|
||||||
|
|
||||||
|
.. [[[cog
|
||||||
|
metadata_example(cog, yaml="""
|
||||||
databases:
|
databases:
|
||||||
mydatabase:
|
mydatabase:
|
||||||
queries:
|
queries:
|
||||||
|
@ -317,6 +508,47 @@ Here's an example configuration (this time using ``metadata.yaml`` since that pr
|
||||||
:_actor_id, :message, :_now_datetime_utc
|
:_actor_id, :message, :_now_datetime_utc
|
||||||
)
|
)
|
||||||
write: true
|
write: true
|
||||||
|
""")
|
||||||
|
.. ]]]
|
||||||
|
|
||||||
|
.. tab:: YAML
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
databases:
|
||||||
|
mydatabase:
|
||||||
|
queries:
|
||||||
|
add_message:
|
||||||
|
allow:
|
||||||
|
id: "*"
|
||||||
|
sql: |-
|
||||||
|
INSERT INTO messages (
|
||||||
|
user_id, message, datetime
|
||||||
|
) VALUES (
|
||||||
|
:_actor_id, :message, :_now_datetime_utc
|
||||||
|
)
|
||||||
|
write: true
|
||||||
|
|
||||||
|
.. tab:: JSON
|
||||||
|
|
||||||
|
.. code-block:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"databases": {
|
||||||
|
"mydatabase": {
|
||||||
|
"queries": {
|
||||||
|
"add_message": {
|
||||||
|
"allow": {
|
||||||
|
"id": "*"
|
||||||
|
},
|
||||||
|
"sql": "INSERT INTO messages (\n user_id, message, datetime\n) VALUES (\n :_actor_id, :message, :_now_datetime_utc\n)",
|
||||||
|
"write": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.. [[[end]]]
|
||||||
|
|
||||||
The form presented at ``/mydatabase/add_message`` will have just a field for ``message`` - the other parameters will be populated by the magic parameter mechanism.
|
The form presented at ``/mydatabase/add_message`` will have just a field for ``message`` - the other parameters will be populated by the magic parameter mechanism.
|
||||||
|
|
||||||
|
|
1
setup.py
1
setup.py
|
@ -76,6 +76,7 @@ setup(
|
||||||
"blacken-docs",
|
"blacken-docs",
|
||||||
"sphinx-copybutton",
|
"sphinx-copybutton",
|
||||||
"sphinx-inline-tabs",
|
"sphinx-inline-tabs",
|
||||||
|
"ruamel.yaml",
|
||||||
],
|
],
|
||||||
"test": [
|
"test": [
|
||||||
"pytest>=5.2.2",
|
"pytest>=5.2.2",
|
||||||
|
|
Ładowanie…
Reference in New Issue