Django Apps

As the core user guides including the Introduction have demonstrated it is easy to display panel apps in the notebook, launch them from an interactive Python prompt and deploy them as a standalone app from the commandline. In order to embed a bokeh app in Django deployment we have to do a bit more work.

Note that currently, the first (and only) example here does not cover integration between param and django models.

To run the example app yourself, you will first need to install django 2 (e.g. conda install "django=2").

sliders app

Based on a standard django2 app template, the sliders app shows how to integrate panel with a django view; there's no interaction between param and django models.

The sliders app is in examples/apps/django2/sliders, which is based on a standard django2 app template. We will cover the following additions/modifications to the django2 app template:

  • sliders/ a parameterized object (representing your pre-existing code)

  • sliders/ creates a bokeh app function from the SineWave class

  • sliders/ how a django app can import and use bokeh server

  • sliders/ and templates/base.html: getting the bokeh app into a django view

You should be able to run this app yourself by changing to the examples/apps/django2 directory and then running: python runserver; visit http://localhost:8000/sliders in your browser to try the app.

screenshot of sliders app

To start with, in sliders/ we create a parameterized object to serve as a placeholder for your own, existing code:

In [1]:
import param
import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import figure

class SineWave(param.Parameterized):

    offset = param.Number(default=0.0, bounds=(-5.0,5.0))
    amplitude = param.Number(default=1.0, bounds=(-5.0,5.0))
    phase = param.Number(default=0.0,bounds=(0.0,2*np.pi))
    frequency = param.Number(default=1.0, bounds=(0.1, 5.1))
    N = param.Integer(default=200, bounds=(0,None))
    x_range = param.Range(default=(0, 4*np.pi),bounds=(0,4*np.pi))
    y_range = param.Range(default=(-2.5,2.5),bounds=(-10,10))

    def __init__(self, **params):
        super(SineWave, self).__init__(**params)
        x, y = self.sine()
        self.cds = ColumnDataSource(data=dict(x=x, y=y))
        self.plot = figure(plot_height=400, plot_width=400,
                           x_range=self.x_range, y_range=self.y_range)
        self.plot.line('x', 'y', source=self.cds, line_width=3, line_alpha=0.6)

    @param.depends('N', 'frequency', 'amplitude', 'offset', 'phase', 'x_range', 'y_range', watch=True)
    def update_plot(self):
        x, y = self.sine() = dict(x=x, y=y)
        self.plot.x_range.start, self.plot.x_range.end = self.x_range
        self.plot.y_range.start, self.plot.y_range.end = self.y_range

    def sine(self):
        x = np.linspace(0, 4*np.pi, self.N)
        y = self.amplitude*np.sin(self.frequency*x + self.phase) + self.offset
        return x, y

We then create an instance of the class, use it to declare a panel from the parameters and the bokeh plot and create a root model:

def app(doc):
    sw = SineWave()
    row = pn.Row(sw.param, sw.plot)

The first Django-specific aspect of our example is to show how a Django app can import and use bokeh server. This is based on, which shows how to embed bokeh in a flask app.

from django.apps import AppConfig

from bokeh.server.server import Server

from tornado.ioloop import IOLoop

from . import bk_sliders
from . import bk_config

def bk_worker():
    # Note: num_procs must be 1; see e.g. for num_procs>1
    server = Server({'/bk_sliders_app':},

class Sliders(AppConfig):
    name = 'sliders'
    def ready(self):
        from threading import Thread

Here, localhost:8000 is the address of the Django app. Note also we have made a simple config file,, for bokeh server settings:

server = dict(
    address = "localhost",
    port = 5006

Finally, in sliders/ we create a view to display the bokeh sliders app:

from django.shortcuts import render

from bokeh.embed import server_document

from . import bk_config

def sliders(request):
    return render(request, 'base.html', {
        "server_script": server_document('http://%s:%s/bk_sliders_app'%(bk_config.server['address'],

The corresponding template is in templates/base.html:

{% block content %}
{% endblock %}

Right click to download this notebook from GitHub.