# bokeh-django
Support for running Bokeh apps with Django
## Introduction
Both Bokeh and Django are web frameworks that can be used independently to build and host web applications. They each have their own strengths and the purpose of the ``bokeh_django`` package is to integrate these two frameworks so their strengths can be used together.
## Installation
```commandline
pip install bokeh-django
```
## Configuration
This documentation assumes that you have already started a [Django project](https://docs.djangoproject.com/en/4.2/intro/tutorial01/).
`bokeh-django` enables you to define routes (URLs) in your Django project that will map to Bokeh applications or embed Bokeh applications into a template rendered by Django. However, before defining the routes there are several configuration steps that need to be completed first.
1. Configure ``INSTALLED_APPS``:
In the ``settings.py`` file ensure that both ``channels`` and ``bokeh_django`` are added to the ``INSTALLED_APPS`` list:
```python
INSTALLED_APPS = [
...,
'channels',
'bokeh_django',
]
```
2. Set Up an ASGI Application:
By default, the Django project will be configured to use a WSGI application, but the ``startproject`` command should have also created an ``asgi.py`` file.
In ``settings.py`` change the ``WSGI_APPLICATION`` setting to ``ASGI_APPLICATION`` and modify the path accordingly. It should look something like this:
```python
ASGI_APPLICATION = 'mysite.asgi.application'
```
Next, modify the contents of the ``asgi.py`` file to get the URL patterns from the ``bokeh_django`` app config. Something similar to this will work:
```python
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.apps import apps
bokeh_app_config = apps.get_app_config('bokeh_django')
application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(URLRouter(bokeh_app_config.routes.get_websocket_urlpatterns())),
'http': AuthMiddlewareStack(URLRouter(bokeh_app_config.routes.get_http_urlpatterns())),
})
```
3. Configure Static Files:
Both Bokeh and Django have several ways of configuring serving static resources. This documentation will describe several possible configuration approaches.
The Bokeh [``resources`` setting](https://docs.bokeh.org/en/latest/docs/reference/settings.html#resources) can be set to one of several values (e.g ``server``, ``inline``, ``cdn``), the default is ``cdn``. If this setting is set to ``inline``, or ``cdn`` then Bokeh resources will be served independently of Django resources. However, if the Bokeh ``resources`` setting is set to ``server``, then the Bokeh resources are served up by the Django server in the same way that the Django static resources are and so Django must be configured to be able to find the Bokeh resources.
To specify the Bokeh ``resources`` setting add the following to the Django ``settings.py`` file:
```python
from bokeh.settings import settings as bokeh_settings
bokeh_settings.resources = 'server'
```
If the Bokeh ``resources`` setting is set to ``server`` then we must add the location of the Bokeh resources to the ``STATICFILES_DIRS`` setting:
```python
from bokeh.settings import settings as bokeh_settings
try:
bokeh_js_dir = bokeh_settings.bokehjs_path()
except AttributeError:
# support bokeh versions < 3.4
bokeh_js_dir = bokeh_settings.bokehjsdir()
STATICFILES_DIRS = [
...,
bokeh_js_dir,
]
```
Django can be configured to automatically find and collect static files using the [``staticfiles`` app](https://docs.djangoproject.com/en/4.2/ref/contrib/staticfiles/), or the static file URL patterns can be explicitly added to the list of ``urlpatterns`` in the ``urls.py`` file.
To explicitly add the static file ``urlpatterns`` add the following to the ``urls.py`` file:
```python
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
from bokeh_django import static_extensions
urlpatterns = [
...,
*static_extensions(),
*staticfiles_urlpatterns(),
]
```
Be sure that the ``static_extensions`` are listed before the ``staticfiles_urlpatterns``.
Alternatively, you can configure the [``staticfiles`` app](https://docs.djangoproject.com/en/4.2/ref/contrib/staticfiles/) by adding ``'django.contrib.staticfiles',`` to ``INSTALLED_APPS``:
```python
INSTALLED_APPS = [
...,
'django.contrib.staticfiles',
'channels',
'bokeh_django',
]
```
Next add ``bokeh_django.static.BokehExtensionFinder`` to the ``STATICFILES_FINDERS`` setting. The default value for ``STATICFILES_FINDERS`` has two items. If you override the default by adding the ``STATICFILES_FINDERS`` setting to your ``settings.py`` file, then be sure to also list the two default values in addition to the ``BokehExtensionFinder``:
```python
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
'bokeh_django.static.BokehExtensionFinder',
)
```
## Define Routes
Bokeh applications are integrated into Django through routing or URLs.
In a Django app, the file specified by the ``ROOT_URLCONF`` setting (e.g. ``urls.py``) must define ``urlpatterns`` which is a sequence of ``django.url.path`` and/or ``django.url.re_path`` objects. When integrating a Django app with Bokeh, the ``urls.py`` file must also define ``bokeh_apps`` as a sequence of ``bokeh_django`` routing objects. This should be done using the ``bokeh_djagno.document`` and/or ``bokeh_django.autoload`` functions.
### Document
The first way to define a route is to use ``bokeh_django.document``, which defines a route to a Bokeh app (as either a file-path or a function).
```python
from bokeh_django import document
from .views import my_bokeh_app_function
bokeh_apps = [
document('url-pattern/', '/path/to/bokeh/app.py'),
document('another-url-pattern/', my_bokeh_app_function)
]
```
When using the ``document`` route Django will route the URL directly to the Bokeh app and all the rendering will be handled by Bokeh.
### Directory
An alternative way to create ``document`` routes is to use ``bokeh_django.directory`` to automatically create a ``document`` route for all the bokeh apps found in a directory. In this case the file name will be used as the URL pattern.
```python
from bokeh_django import directory
bokeh_apps = directory('/path/to/bokeh/apps/')
```
### Autoload
To integrate more fully into a Django application routes can be created using ``autoload``. This allows the Bokeh application to be embedded in a template that is rendered by Django. This has the advantage of being able to leverage Django capabilities in the view and the template, but is slightly more involved to set up. There are five components that all need to be configured to work together: the [Bokeh handler](#bokeh-handler), the [Django view](#django-view), the [template](#template), the [Django URL path](#django-url-path), and the [Bokeh URL route](#bokeh-url-route).
#### Bokeh Handler
The handler is a function (or any callable) that accepts a ``bokeh.document.Document`` object and configures it with the Bokeh content that should be embedded. This is done by adding a Bokeh object as the document root:
```python
from bokeh.document import Document
from bokeh.layouts import column
from bokeh.models import Slider
def bokeh_handler(doc: Document) -> None:
slider = Slider(start=0, end=30, value=0, step=1, title="Example")
doc.add_root(column(slider))
```
The handler can also embed a Panel object. In this case the document is passed in to the ``server_doc`` method of the Panel object:
```python
import panel as pn
def panel_handler(doc: Document) -> None:
pn.Row().server_doc(doc)
```
#### Django View
The view is a Django function that accepts a ``request`` object and returns a ``response``. A view that embeds a Bokeh app must create a ``bokeh.embed.server_document`` and pass it in the context to the template when rendering the response.
```python
from bokeh.embed import server_document
from django.shortcuts import render
def view_function(request):
script = server_document(request.build_absolute_uri())
return render(request, "embed.html", dict(script=script))
```
#### Template
The template document is a Django HTML template (e.g. ``"embed.html"``) that will be rendered by Django. It can be as complex as desired, but at the very least must render the ``script`` that was passed in from the context:
```html
<!doctype html>
<html lang="en">
<body>
{{ script|safe }}
</body>
</html>
```
#### Django URL Path
The [Django URL Path](#django-url-path) is a ``django.url.path`` or ``django.url.re_path`` object that is included in the ``urlpatters`` sequence and that maps a URL pattern to the [Django View](#django-view) as would normally be done with Django.
```python
urlpatterns = [
path("embedded-bokeh-app/", views.view_function),
]
```
#### Bokeh URL Route
The [Bokeh URL Route](#bokeh-url-route) is a ``bokeh_django.autoload`` object that is included in the ``bokeh_apps`` sequence and that maps a URL pattern to the [Bokeh handler](#bokeh-handler).
```python
from bokeh_django import autoload
bokeh_apps = [
autoload("embedded-bokeh-app/", views.handler)
]
```
Note that the URL pattern should be the same URL pattern that was used in the corresponding [Django URL Path](#django-url-path). In reality the URL pattern must match the URL that the ``server_document`` script is configured with in the [Django View](#django-view). Normally, it is easiest to use the URL from the ``request`` object (e.g. ``script = server_document(request.build_absolute_uri())``), which is the URL of the corresponding [Django URL Path](#django-url-path).
Raw data
{
"_id": null,
"home_page": null,
"name": "bokeh-django",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": null,
"keywords": "Bokeh, Django, Channels, web, visualization",
"author": null,
"author_email": "Bokeh Team <info@bokeh.org>",
"download_url": "https://files.pythonhosted.org/packages/4e/ac/0b084305154d00233bf5d7a5d4485bbdcdfde87d07f1b1c5e73ca449cd0c/bokeh_django-0.2.1.tar.gz",
"platform": null,
"description": "# bokeh-django\nSupport for running Bokeh apps with Django\n\n## Introduction\nBoth Bokeh and Django are web frameworks that can be used independently to build and host web applications. They each have their own strengths and the purpose of the ``bokeh_django`` package is to integrate these two frameworks so their strengths can be used together. \n\n## Installation\n\n```commandline\npip install bokeh-django\n```\n\n## Configuration\n\nThis documentation assumes that you have already started a [Django project](https://docs.djangoproject.com/en/4.2/intro/tutorial01/).\n\n`bokeh-django` enables you to define routes (URLs) in your Django project that will map to Bokeh applications or embed Bokeh applications into a template rendered by Django. However, before defining the routes there are several configuration steps that need to be completed first.\n\n1. Configure ``INSTALLED_APPS``:\n\n In the ``settings.py`` file ensure that both ``channels`` and ``bokeh_django`` are added to the ``INSTALLED_APPS`` list:\n\n ```python\n INSTALLED_APPS = [\n ...,\n 'channels',\n 'bokeh_django',\n ]\n ```\n\n2. Set Up an ASGI Application:\n\n By default, the Django project will be configured to use a WSGI application, but the ``startproject`` command should have also created an ``asgi.py`` file.\n\n In ``settings.py`` change the ``WSGI_APPLICATION`` setting to ``ASGI_APPLICATION`` and modify the path accordingly. It should look something like this:\n\n ```python\n ASGI_APPLICATION = 'mysite.asgi.application'\n ```\n \n Next, modify the contents of the ``asgi.py`` file to get the URL patterns from the ``bokeh_django`` app config. Something similar to this will work:\n\n ```python\n from channels.auth import AuthMiddlewareStack\n from channels.routing import ProtocolTypeRouter, URLRouter\n from django.apps import apps\n \n bokeh_app_config = apps.get_app_config('bokeh_django')\n \n application = ProtocolTypeRouter({\n 'websocket': AuthMiddlewareStack(URLRouter(bokeh_app_config.routes.get_websocket_urlpatterns())),\n 'http': AuthMiddlewareStack(URLRouter(bokeh_app_config.routes.get_http_urlpatterns())),\n })\n ```\n\n3. Configure Static Files:\n\n Both Bokeh and Django have several ways of configuring serving static resources. This documentation will describe several possible configuration approaches.\n \n The Bokeh [``resources`` setting](https://docs.bokeh.org/en/latest/docs/reference/settings.html#resources) can be set to one of several values (e.g ``server``, ``inline``, ``cdn``), the default is ``cdn``. If this setting is set to ``inline``, or ``cdn`` then Bokeh resources will be served independently of Django resources. However, if the Bokeh ``resources`` setting is set to ``server``, then the Bokeh resources are served up by the Django server in the same way that the Django static resources are and so Django must be configured to be able to find the Bokeh resources.\n \n To specify the Bokeh ``resources`` setting add the following to the Django ``settings.py`` file:\n \n ```python\n from bokeh.settings import settings as bokeh_settings\n \n bokeh_settings.resources = 'server'\n ```\n \n If the Bokeh ``resources`` setting is set to ``server`` then we must add the location of the Bokeh resources to the ``STATICFILES_DIRS`` setting:\n \n ```python\n from bokeh.settings import settings as bokeh_settings\n \n try:\n bokeh_js_dir = bokeh_settings.bokehjs_path()\n except AttributeError:\n # support bokeh versions < 3.4\n bokeh_js_dir = bokeh_settings.bokehjsdir()\n \n STATICFILES_DIRS = [\n ...,\n bokeh_js_dir,\n ]\n ```\n \n Django can be configured to automatically find and collect static files using the [``staticfiles`` app](https://docs.djangoproject.com/en/4.2/ref/contrib/staticfiles/), or the static file URL patterns can be explicitly added to the list of ``urlpatterns`` in the ``urls.py`` file. \n \n To explicitly add the static file ``urlpatterns`` add the following to the ``urls.py`` file:\n \n ```python\n from django.contrib.staticfiles.urls import staticfiles_urlpatterns\n from bokeh_django import static_extensions\n \n urlpatterns = [\n ...,\n *static_extensions(),\n *staticfiles_urlpatterns(),\n ]\n ```\n\n Be sure that the ``static_extensions`` are listed before the ``staticfiles_urlpatterns``.\n\n Alternatively, you can configure the [``staticfiles`` app](https://docs.djangoproject.com/en/4.2/ref/contrib/staticfiles/) by adding ``'django.contrib.staticfiles',`` to ``INSTALLED_APPS``:\n\n ```python\n INSTALLED_APPS = [\n ...,\n 'django.contrib.staticfiles',\n 'channels',\n 'bokeh_django',\n ]\n ```\n \n Next add ``bokeh_django.static.BokehExtensionFinder`` to the ``STATICFILES_FINDERS`` setting. The default value for ``STATICFILES_FINDERS`` has two items. If you override the default by adding the ``STATICFILES_FINDERS`` setting to your ``settings.py`` file, then be sure to also list the two default values in addition to the ``BokehExtensionFinder``:\n\n ```python\n STATICFILES_FINDERS = (\n \"django.contrib.staticfiles.finders.FileSystemFinder\",\n \"django.contrib.staticfiles.finders.AppDirectoriesFinder\",\n 'bokeh_django.static.BokehExtensionFinder',\n )\n ```\n\n## Define Routes\n\nBokeh applications are integrated into Django through routing or URLs. \n \nIn a Django app, the file specified by the ``ROOT_URLCONF`` setting (e.g. ``urls.py``) must define ``urlpatterns`` which is a sequence of ``django.url.path`` and/or ``django.url.re_path`` objects. When integrating a Django app with Bokeh, the ``urls.py`` file must also define ``bokeh_apps`` as a sequence of ``bokeh_django`` routing objects. This should be done using the ``bokeh_djagno.document`` and/or ``bokeh_django.autoload`` functions.\n\n### Document\n \nThe first way to define a route is to use ``bokeh_django.document``, which defines a route to a Bokeh app (as either a file-path or a function). \n\n```python\nfrom bokeh_django import document\nfrom .views import my_bokeh_app_function\n\nbokeh_apps = [\n document('url-pattern/', '/path/to/bokeh/app.py'),\n document('another-url-pattern/', my_bokeh_app_function) \n]\n```\nWhen using the ``document`` route Django will route the URL directly to the Bokeh app and all the rendering will be handled by Bokeh.\n\n### Directory\n\nAn alternative way to create ``document`` routes is to use ``bokeh_django.directory`` to automatically create a ``document`` route for all the bokeh apps found in a directory. In this case the file name will be used as the URL pattern.\n\n```python\nfrom bokeh_django import directory\n\nbokeh_apps = directory('/path/to/bokeh/apps/')\n```\n\n### Autoload\n\nTo integrate more fully into a Django application routes can be created using ``autoload``. This allows the Bokeh application to be embedded in a template that is rendered by Django. This has the advantage of being able to leverage Django capabilities in the view and the template, but is slightly more involved to set up. There are five components that all need to be configured to work together: the [Bokeh handler](#bokeh-handler), the [Django view](#django-view), the [template](#template), the [Django URL path](#django-url-path), and the [Bokeh URL route](#bokeh-url-route).\n\n#### Bokeh Handler\n\nThe handler is a function (or any callable) that accepts a ``bokeh.document.Document`` object and configures it with the Bokeh content that should be embedded. This is done by adding a Bokeh object as the document root:\n\n```python\nfrom bokeh.document import Document\nfrom bokeh.layouts import column\nfrom bokeh.models import Slider\n\ndef bokeh_handler(doc: Document) -> None:\n slider = Slider(start=0, end=30, value=0, step=1, title=\"Example\")\n doc.add_root(column(slider))\n```\n\nThe handler can also embed a Panel object. In this case the document is passed in to the ``server_doc`` method of the Panel object:\n\n```python\nimport panel as pn\ndef panel_handler(doc: Document) -> None:\n pn.Row().server_doc(doc)\n```\n\n#### Django View\n\nThe view is a Django function that accepts a ``request`` object and returns a ``response``. A view that embeds a Bokeh app must create a ``bokeh.embed.server_document`` and pass it in the context to the template when rendering the response.\n\n```python\nfrom bokeh.embed import server_document\nfrom django.shortcuts import render\n\ndef view_function(request):\n script = server_document(request.build_absolute_uri())\n return render(request, \"embed.html\", dict(script=script))\n```\n\n#### Template\n\nThe template document is a Django HTML template (e.g. ``\"embed.html\"``) that will be rendered by Django. It can be as complex as desired, but at the very least must render the ``script`` that was passed in from the context:\n\n```html\n<!doctype html>\n<html lang=\"en\"> \n<body>\n {{ script|safe }}\n</body>\n</html>\n```\n\n#### Django URL Path\n\nThe [Django URL Path](#django-url-path) is a ``django.url.path`` or ``django.url.re_path`` object that is included in the ``urlpatters`` sequence and that maps a URL pattern to the [Django View](#django-view) as would normally be done with Django.\n\n```python\nurlpatterns = [\n path(\"embedded-bokeh-app/\", views.view_function),\n]\n```\n\n#### Bokeh URL Route\n\nThe [Bokeh URL Route](#bokeh-url-route) is a ``bokeh_django.autoload`` object that is included in the ``bokeh_apps`` sequence and that maps a URL pattern to the [Bokeh handler](#bokeh-handler).\n\n```python\nfrom bokeh_django import autoload\n\nbokeh_apps = [\n autoload(\"embedded-bokeh-app/\", views.handler) \n]\n```\n\nNote that the URL pattern should be the same URL pattern that was used in the corresponding [Django URL Path](#django-url-path). In reality the URL pattern must match the URL that the ``server_document`` script is configured with in the [Django View](#django-view). Normally, it is easiest to use the URL from the ``request`` object (e.g. ``script = server_document(request.build_absolute_uri())``), which is the URL of the corresponding [Django URL Path](#django-url-path).\n",
"bugtrack_url": null,
"license": null,
"summary": "Utility to integrate Bokeh with Django Channels",
"version": "0.2.1",
"project_urls": {
"Homepage": "https://github.com/bokeh/bokeh-django"
},
"split_keywords": [
"bokeh",
" django",
" channels",
" web",
" visualization"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "5fe6874ed997c449cf985638fe6df585010e2366b76b574789986efe3b9a28c8",
"md5": "57cf8f6021cdf3beb56697b303dfed7b",
"sha256": "c69437ac8f251d1266de025342c4d8235415b8538236876ef94728fbd8bb2802"
},
"downloads": -1,
"filename": "bokeh_django-0.2.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "57cf8f6021cdf3beb56697b303dfed7b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 15531,
"upload_time": "2025-10-16T23:51:43",
"upload_time_iso_8601": "2025-10-16T23:51:43.272837Z",
"url": "https://files.pythonhosted.org/packages/5f/e6/874ed997c449cf985638fe6df585010e2366b76b574789986efe3b9a28c8/bokeh_django-0.2.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "4eac0b084305154d00233bf5d7a5d4485bbdcdfde87d07f1b1c5e73ca449cd0c",
"md5": "d22fa329f47cda1e664581a9f91c29a4",
"sha256": "d97221b86a63b8398a1a2d784d93807b14c910541da76c260b83b5b88be8679a"
},
"downloads": -1,
"filename": "bokeh_django-0.2.1.tar.gz",
"has_sig": false,
"md5_digest": "d22fa329f47cda1e664581a9f91c29a4",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 16567,
"upload_time": "2025-10-16T23:51:44",
"upload_time_iso_8601": "2025-10-16T23:51:44.359622Z",
"url": "https://files.pythonhosted.org/packages/4e/ac/0b084305154d00233bf5d7a5d4485bbdcdfde87d07f1b1c5e73ca449cd0c/bokeh_django-0.2.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-16 23:51:44",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "bokeh",
"github_project": "bokeh-django",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "bokeh-django"
}