URL Maps API¶
Last Updated: September 2019
A UrlMap
is a mapping between a URL and a function or class that is responsible for handling a request. When a request is submitted to Tethys, it matches the URL of that request against a list of UrlMaps
and calls the function or class that the matching UrlMap
points to.
Tethys usually manages url_maps
from the app.py
file of each individual app using a UrlMap
constructor. This constructor normally accepts a name
, a url
, and a controller
. However, there are other parameters such as protocol
, regex
, handler
, and handler_type
. This section provides information on how to use the url_maps
API.
URL Maps Contructor¶
- class tethys_apps.base.url_map.UrlMapBase(name, url, controller, protocol='http', regex=None, handler=None, handler_type=None)¶
Abstract URL base class for Tethys app controllers and consumers
- __init__(name, url, controller, protocol='http', regex=None, handler=None, handler_type=None)¶
Constructor
- Parameters
name (str) -- Name of the url map. Letters and underscores only (_). Must be unique within the app.
url (str) -- Url pattern to map the endpoint for the controller or consumer.
controller (str) -- Dot-notation path to the controller function or consumer class.
protocol (str) -- 'http' for consumers or 'websocket' for consumers. Default is http.
regex (str or iterable, optional) -- Custom regex pattern(s) for url variables. If a string is provided, it will be applied to all variables. If a list or tuple is provided, they will be applied in variable order.
handler (str) -- Dot-notation path a handler function. A handler is associated to a specific controller and contains the main logic for creating and establishing a communication between the client and the server.
handler_type (str) -- Tethys supported handler type. 'bokeh' is the only handler type currently supported.
URL Maps Methods¶
The url_maps
methods is tightly related to the App Base Class API.
- TethysBase.url_maps()
Override this method to define the URL Maps for your app. Your
UrlMap
objects must be created from aUrlMap
class that is bound to theroot_url
of your app. Use theurl_map_maker()
function to create the boundUrlMap
class. If you generate your app project from the scaffold, this will be done automatically. Starting in Tethys 3.0, theWebSocket
protocol is supported along with theHTTP
protocol. To create aWebSocket UrlMap
, follow the same pattern used for theHTTP
protocol. In addition, provide aConsumer
path in the controllers parameter as well as aWebSocket
string value for the new protocol parameter for theWebSocket UrlMap
. Alternatively, Bokeh Server can also be integrated into Tethys usingDjango Channels
andWebsockets
. Tethys will automatically set these up for you if ahandler
andhandler_type
parameters are provided as part of theUrlMap
.- Returns
A list or tuple of
UrlMap
objects.- Return type
iterable
Example:
from tethys_sdk.base import url_map_maker class MyFirstApp(TethysAppBase): def url_maps(self): """ Example url_maps method. """ # Create UrlMap class that is bound to the root url. UrlMap = url_map_maker(self.root_url) url_maps = ( UrlMap(name='home', url='my-first-app', controller='my_first_app.controllers.home', ), UrlMap(name='home_ws', url='my-first-ws', controller='my_first_app.controllers.HomeConsumer', protocol='websocket' ), UrlMap(name='bokeh_handler', url='my-first-app/bokeh-example', controller='my_first_app.controllers.bokeh_example', handler='my_first_app.controllers.bokeh_example_handler', handler_type='bokeh' ), ) return url_maps
Websockets¶
Tethys Platform supports WebSocket connections using Django Channels. The WebSocket protocol provides a persistent connection between the client and the server. In contrast to the traditional HTTP protocol, the webscoket protocol allows for bidirectional communication between the client and the server (i.e. the server can trigger a response without the client sending a request). Django Channels uses Consumers to structure code and handle client/server communication in a similar way Controllers are used with the HTTP protocol.
Note
For more information about Django Channels and Consumers visit the Django Channels docummentation.
Note
For more information on establishing a WebSocket connection see the JavaScript WebSocket API. Alternatively, other existing JavaScript or Python WebSocket clients can we used.
Tip
To create a URL mapping using the WebSocket protocol see the example provided in the App Base Class API documentation.
Tip
For an example demonstrating all the necessary components to integrating websockets into your app see WebSockets Concepts.
Bokeh Integration¶
Bokeh Integration in Tethys takes advantage of Websockets
and Django Channels
to leverage Bokeh's flexible architecture. In particular, the ability to sync model objects to the client allows for a responsive user interface that can receive updates from the server using Python. This is referred to as Bokeh Server
in the Bokeh Documentation.
Tethys facilitates the use of the Bokeh Server
component of Bokeh
by taking care of creating the routings necessary to link the models and the front end bokeh models. This is done by providing a handler
in addition that the other common parameters in a UrlMap
.
Note
Interactive Bokeh
visualization tools can be entirely created using only Python with the help of Bokeh Server
. However, this usually requires the use of an additional server (Tornado
). One of the alternatives to Tornado
is using Django Channels
, which is already supported with Tethys. Therefore, interactive Bokeh
models along with the all the advantages of using Bokeh Server
can be leveraged in Tethys without the need of an additional server.
class MyFirstApp(TethysAppBase):
def url_maps(self):
"""
Example url_maps method.
"""
# Create UrlMap class that is bound to the root url.
UrlMap = url_map_maker(self.root_url)
url_maps = (
...
UrlMap(name='bokeh_handler',
url='my-first-app/bokeh-example',
controller='my_first_app.controllers.bokeh_example',
handler='my_first_app.controllers.bokeh_example_handler',
handler_type='bokeh'
),
)
return url_maps
A Handler
in this context represents a function that contains the main logic needed for a Bokeh model to be displayed. It contains the model or group of models as well as the callback functions that will help link them to the client. Handlers
are added to the Bokeh Document
, the smallest serialization unit in Bokeh Server
. This same Document
is later retrieved and added to the template variables in the Controller
that will be linked to the Handler function
using Bokeh's server_document function.
A Bokeh Document comes with a ``Bokeh Request
. This request contains most of the common attibutes of a normal HTTPRequest
, and can be easily converted to HTTP using the with_request
decorator from tethys_sdk.base
. A second handler decorator named with_workspaces
can be used to add user_workspace
and app_workspace
to the Bokeh Document
. This latter decorator will also convert the Bokeh Request
of the Document
to an HTTPRequest, meaning it will do the same thing as the ``with_request
decorator besides adding workspaces.
The example below adds a column layout containing a slider and a plot. A callback function linked to the slider value change event and a demonstration of how to use the with_workspaces
decorator are also included.
from tethys_sdk.base import with_workspaces
...
@with_workspaces
def home_handler(doc):
# create data source for plot
data = {'x': [0, 1, 2, 3], 'y': [0, 10, 20, 30]}
source = ColumnDataSource(data=data)
# create plot
plot = figure(x_axis_type="linear", y_range=(0, 30), title="Bokeh Plot")
plot.line(x="x", y="y", source=source)
# callback function
def callback(attr: str, old: Any, new: Any) -> None:
if new == 1:
data['y'] = [0, 10, 20, 30]
else:
data['y'] = [i * new for i in [0, 10, 20, 30]]
source.data = dict(ColumnDataSource(data=data).data)
plot.y_range.end = max(data['y'])
# create slider and add callback to it
slider = Slider(start=1, end=5, value=1, step=1, title="Bokeh Slider")
slider.on_change("value", callback)
# attributes available when using "with_workspaces" decorator
request = doc.request
user_workspace = doc.user_workspace
app_workspace = doc.app_workspace
# add layout with bokeh models to document
doc.add_root(column(slider, plot))
The controller
from the same UrlMap
where the handler
is defined needs to provide a mechanism to load the Bokeh
models to the client.
def home(request):
...
script = server_document(request.build_absolute_uri())
context = {
'script': script
}
return render(request, 'test_app/home.html', context)
Tip
For more information regarding Bokeh Server and available models visit the Bokeh Server Documentation and the Bokeh model widgets reference guide.