Populate docs/ from 0.65.2

This commit is contained in:
Automated 2025-11-05 18:51:58 +00:00
commit 264bba5db2
26 changed files with 883 additions and 5641 deletions

View file

@ -7,7 +7,7 @@ Datasette treats SQLite database files as read-only and immutable. This means it
The easiest way to execute custom SQL against Datasette is through the web UI. The database index page includes a SQL editor that lets you run any SELECT query you like. You can also construct queries using the filter interface on the tables page, then click "View and edit SQL" to open that query in the custom SQL editor.
Note that this interface is only available if the :ref:`actions_execute_sql` permission is allowed. See :ref:`authentication_permissions_execute_sql`.
Note that this interface is only available if the :ref:`permissions_execute_sql` permission is allowed.
Any Datasette SQL query is reflected in the URL of the page, allowing you to bookmark them, share them with others and navigate through previous queries using your browser back button.
@ -53,29 +53,22 @@ If you want to bundle some pre-written SQL queries with your Datasette-hosted da
The quickest way to create views is with the SQLite command-line interface::
sqlite3 sf-trees.db
::
$ sqlite3 sf-trees.db
SQLite version 3.19.3 2017-06-27 16:48:08
Enter ".help" for usage hints.
sqlite> CREATE VIEW demo_view AS select qSpecies from Street_Tree_List;
<CTRL+D>
You can also use the `sqlite-utils <https://sqlite-utils.datasette.io/>`__ tool to `create a view <https://sqlite-utils.datasette.io/en/stable/cli.html#creating-views>`__::
sqlite-utils create-view sf-trees.db demo_view "select qSpecies from Street_Tree_List"
.. _canned_queries:
Canned queries
--------------
As an alternative to adding views to your database, you can define canned queries inside your ``datasette.yaml`` file. Here's an example:
As an alternative to adding views to your database, you can define canned queries inside your ``metadata.json`` file. Here's an example:
.. [[[cog
from metadata_doc import config_example, config_example
config_example(cog, {
.. code-block:: json
{
"databases": {
"sf-trees": {
"queries": {
@ -85,36 +78,7 @@ As an alternative to adding views to your database, you can define canned querie
}
}
}
})
.. ]]]
.. tab:: datasette.yaml
.. code-block:: yaml
databases:
sf-trees:
queries:
just_species:
sql: select qSpecies from Street_Tree_List
.. tab:: datasette.json
.. code-block:: json
{
"databases": {
"sf-trees": {
"queries": {
"just_species": {
"sql": "select qSpecies from Street_Tree_List"
}
}
}
}
}
.. [[[end]]]
}
Then run Datasette like this::
@ -147,60 +111,38 @@ Here's an example of a canned query with a named parameter:
where neighborhood like '%' || :text || '%'
order by neighborhood;
In the canned query configuration looks like this:
In the canned query metadata (here :ref:`metadata_yaml` as ``metadata.yaml``) it looks like this:
.. code-block:: yaml
.. [[[cog
config_example(cog, """
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
""")
.. ]]]
title: Search neighborhoods
.. tab:: datasette.yaml
Here's the equivalent using JSON (as ``metadata.json``):
.. code-block:: yaml
.. code-block:: json
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:: datasette.json
.. code-block:: json
{
"databases": {
{
"databases": {
"fixtures": {
"queries": {
"neighborhood_search": {
"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"
"queries": {
"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"
}
}
}
}
}
}
.. [[[end]]]
}
Note that we are using SQLite string concatenation here - the ``||`` operator - to add wildcard ``%`` characters to the string provided by the user.
@ -211,13 +153,12 @@ 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:
.. [[[cog
config_example(cog, """
.. code-block:: yaml
databases:
fixtures:
queries:
neighborhood_search:
title: Search neighborhoods
params:
- text
sql: |-
@ -226,49 +167,7 @@ You can alternatively provide an explicit list of named parameters using the ``"
join facet_cities on facetable.city_id = facet_cities.id
where neighborhood like '%' || :text || '%'
order by neighborhood
""")
.. ]]]
.. tab:: datasette.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:: datasette.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]]]
title: Search neighborhoods
.. _canned_queries_options:
@ -293,56 +192,21 @@ 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``:
.. [[[cog
config_example(cog, """
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;
""")
.. ]]]
.. code-block:: json
.. tab:: datasette.yaml
.. 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:: datasette.json
.. code-block:: json
{
"databases": {
{
"databases": {
"fixtures": {
"queries": {
"neighborhood_search": {
"fragment": "fragment-goes-here",
"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;"
"queries": {
"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",
"hide_sql": true
}
}
}
}
}
}
.. [[[end]]]
}
`See here <https://latest.datasette.io/fixtures#queries>`__ for a demo of this in action.
@ -355,132 +219,55 @@ 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.
.. [[[cog
config_example(cog, {
.. code-block:: json
{
"databases": {
"mydatabase": {
"queries": {
"add_name": {
"sql": "INSERT INTO names (name) VALUES (:name)",
"write": True
"write": true
}
}
}
}
})
.. ]]]
.. tab:: datasette.yaml
.. code-block:: yaml
databases:
mydatabase:
queries:
add_name:
sql: INSERT INTO names (name) VALUES (:name)
write: true
.. tab:: datasette.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.
You can customize how Datasette represents success and errors using the following optional properties:
- ``on_success_message`` - the message shown when a query is successful
- ``on_success_message_sql`` - alternative to ``on_success_message``: a SQL query that should be executed to generate the message
- ``on_success_redirect`` - the path or URL the user is redirected to on success
- ``on_error_message`` - the message shown when a query throws an error
- ``on_error_redirect`` - the path or URL the user is redirected to on error
For example:
.. [[[cog
config_example(cog, {
.. code-block:: json
{
"databases": {
"mydatabase": {
"queries": {
"add_name": {
"sql": "INSERT INTO names (name) VALUES (:name)",
"params": ["name"],
"write": True,
"on_success_message_sql": "select 'Name inserted: ' || :name",
"write": true,
"on_success_message": "Name inserted",
"on_success_redirect": "/mydatabase/names",
"on_error_message": "Name insert failed",
"on_error_redirect": "/mydatabase",
"on_error_redirect": "/mydatabase"
}
}
}
}
})
.. ]]]
}
.. tab:: datasette.yaml
.. code-block:: yaml
databases:
mydatabase:
queries:
add_name:
sql: INSERT INTO names (name) VALUES (:name)
params:
- name
write: true
on_success_message_sql: 'select ''Name inserted: '' || :name'
on_success_redirect: /mydatabase/names
on_error_message: Name insert failed
on_error_redirect: /mydatabase
.. tab:: datasette.json
.. code-block:: json
{
"databases": {
"mydatabase": {
"queries": {
"add_name": {
"sql": "INSERT INTO names (name) VALUES (:name)",
"params": [
"name"
],
"write": true,
"on_success_message_sql": "select 'Name inserted: ' || :name",
"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. ``"params"`` is not necessary in the above example, since without it ``"name"`` would be automatically detected from the query.
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 pre-populate form fields when the page first loads using a query string, e.g. ``/mydatabase/add_name?name=Prepopulated``. The user will have to submit the form to execute the query.
If you specify a query in ``"on_success_message_sql"``, that query will be executed after the main query. The first column of the first row return by that query will be displayed as a success message. Named parameters from the main query will be made available to the success message query as well.
.. _canned_queries_magic_parameters:
Magic parameters
@ -513,10 +300,10 @@ Available magic parameters are:
``_random_chars_*`` - e.g. ``_random_chars_128``
A random string of characters of the specified length.
Here's an example configuration that adds a message from the authenticated user, storing various pieces of additional metadata using magic parameters:
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:
.. code-block:: yaml
.. [[[cog
config_example(cog, """
databases:
mydatabase:
queries:
@ -530,49 +317,6 @@ Here's an example configuration that adds a message from the authenticated user,
:_actor_id, :message, :_now_datetime_utc
)
write: true
""")
.. ]]]
.. tab:: datasette.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:: datasette.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.
@ -613,7 +357,7 @@ The JSON response will look like this:
"redirect": "/data/add_name"
}
The ``"message"`` and ``"redirect"`` values here will take into account ``on_success_message``, ``on_success_message_sql``, ``on_success_redirect``, ``on_error_message`` and ``on_error_redirect``, if they have been set.
The ``"message"`` and ``"redirect"`` values here will take into account ``on_success_message``, ``on_success_redirect``, ``on_error_message`` and ``on_error_redirect``, if they have been set.
.. _pagination: