Simple Ajax with cherrypy and jQuery

All the cool kids these days are putting Ajax into their web applications. Ajax is great for when you want to update data on a page without reloading the entire page. Most of the Ajax tutorials use PHP, so I want to show here how easy it is to do Ajax with cherrpy.

Ajax stands for "asynchronous JavaScript and XML," but these days json is often used as a lighter-weight alternative to XML. In this tutorial, I'm therefore going to show how to use the python simplejson library to enable communication between python and JavaScript using json.

What you will need for this tutorial:

You can get cherrypy and simplejson from pypi via easy_install; there's a copy of jQuery in my sample project. The sample project consists of three files, in the following structure:
  + jquery-1.4.2.min.js
  | index.html

First, I'll show the HTML file:

    <title>AJAX with jQuery and cherrypy</title>
    <script type="text/javascript" src="/media/jquery-1.4.2.min.js"></script>
<script type="text/javascript">
    $(function() {
    // When the testform is submitted…
    $("#testform").submit(function() {
        // post the form values via AJAX…
        var postdata = {name: $("#name").val()} ;
        $.post('/submit', postdata, function(data) {
            // and set the title with the result
            $("#title").html(data['title']) ;
        return false ;
    <h1 id="title">What's your name?</h1>

    <form id="testform" action="#" method="post">
        <label for="name">Name:</label>
        <input type="text" id="name" /> <br />

        <input type="submit" value="Set" />

Let's see what this is doing. In the body, you've got a title tag, and bog standard HTML form, which asks for a name.

In the head, you've got an include to the jQuery library, and the following JavaScript code:

    $(function() {
    // When the testform is submitted…
    $("#testform").submit(function() {
        // post the form values via AJAX…
        var postdata = {name: $("#name").val()} ;
        $.post('/submit', postdata, function(data) {
            // and set the title with the result
            $("#title").html(data['title']) ;
        return false ;

The initial $(function() statement is a jQuery construct that says, "When the page loads, execute this anonymous function." That function then creates a callback for the submit event of the element with id "testform" (the form). When the form is submitted, the jQuery post function is executed, which is where the magic happens. is an Ajax method. The first argument is the URL to post to ("/submit"); the second argument is the data to send in the post (the "name" value from the form); and the third argument is the callback to call with the data we receive from the post.

The function then takes this data, and uses its "title" element to update the title of the page.

Next, here's the file:

import cherrypy
import webbrowser
import os
import simplejson
import sys

MEDIA_DIR = os.path.join(os.path.abspath("."), u"media")

class AjaxApp(object):
    def index(self):
        return open(os.path.join(MEDIA_DIR, u'index.html'))

    def submit(self, name):
        cherrypy.response.headers['Content-Type'] = 'application/json'
        return simplejson.dumps(dict(title="Hello, %s" % name))

config = {'/media':
                {'tools.staticdir.on': True,
                 'tools.staticdir.dir': MEDIA_DIR,

def open_page():"")
cherrypy.engine.subscribe('start', open_page)
cherrypy.tree.mount(AjaxApp(), '/', config=config)

First, the AjaxApp class is our application. It's pretty simple, having only two methods: index and submit.

When the index method is called, the app opens the index file and returns it.

The submit method is our Ajax method; when it is called with the form data, we use the information to create a new title, and pass that back as json data using simplejson.dumps. The JavaScript function that called this method can then use the data to update the page content.

This little piece of code is a convenience for development; when you run the cherrpy app, it loads the index page in your web browser.

def open_page():"")
cherrypy.engine.subscribe('start', open_page)

Finally, the last two lines mount the app, and start up the server. The "config" dict tells cherrpy to serve up static files from the "media" dir in the script's home directory.

If you download the sample project, unzip it, and run, you should get the following screen (shown here with the name filled in):

Ajax app -- step1

Ajax app -- step 1

Here it is after filling in the name and clicking Set:

Ajax app -- step 2

Ajax app -- step 2

When to use Ajax

Ajax is useful when you want to update the page content without reloading the entire page. This is useful for CRUD apps when you want to do things like edit items in place, delete items, or add items.

When not to use Ajax

Since Ajax actions don't correspond to URIs, you can't bookmark Ajax actions, send links to friends, or use the back and forward buttons to navigate like in a normal website.

For this reason, avoid Ajax if you want certain application states to be navigable as URIs. For example, if you have a calendar application, and use Ajax to show all the data, the user won't have any way to bookmark an event on December 12th, 2011. Likewise, if you use an Ajax data grid to show tables of data, you won't be able to email your data views to your colleagues.

One middle way is to offer a "permalink" for each Ajax view, which allows for bookmarking, sending links, etc. This still breaks the back-button functionality, but may be worth the trade-off.

15 comments to Simple Ajax with cherrypy and jQuery

  • […] post: The GITS Blog » Simple Ajax with cherrypy and jQuery Posteado por: yoobz on March 7, […]

  • Hey there, thanks for the post, this is just what I was looking for ! Now off to see if I can use this functionality together with openflashcharts… 🙂

  • njr

    This is great: very simple and works exactly as advertised (not as common as we’d all like!)

    Thanks for the post.

  • Jean

    Excellent post. How can I shut down cherrypy by closing the brower?

  • @Jean

    Unfortunately, you can’t. This is because the process isn’t running in the browser; the browser is accessing the cherrpy server, which is what browsers do. You can add a link on your website that will shut down the server (e.g. “Exit Server”), and then have that URL handler shut down cherrypy.

  • Nicholas Key

    Hey Ryan,

    I tried to access the page via another IP address by doing “ifconfig | grep inet” (eg, instead of using

    But I’m not able to do a GET from


  • Nicholas: You need to modify the config like this

    ‘global’: {
    ‘server.socket_port’ : 8080,
    ‘server.socket_host’: “”

  • Adnan

    I am fairly new to python let alone using cherrypy so please excuse me if the the question is too dumb. I actually wanted to know how we can run other pages on the server…for example I want to navigate to some page named setting.html from index.html which ofcourse uses function from the same python script.

  • @Adnan

    Yes, this is quite simple with cherrypy. You would do something like this in your Python script:

    class AjaxApp(object):
        def index(self):
            return open(os.path.join(MEDIA_DIR, u'index.html'))
        def setting(self):
            return open(os.path.join(MEDIA_DIR, u'setting.html'))

    Then in your index.html file, you could add a link to “setting” in the form <a href=”/setting” >Settings</a>

  • Adnan

    Thank you very much for the reply….but there is a new problem now…Is it possible to enable it to be able to run ANY page on cherrypy without having to difine it in the script???….like in apache we just place the html files in htdocs…is it possible to make a directory like this for cherrypy??

  • @Adnan

    Yes, it is quite simple to serve static content in cherrypy. You can serve directories, file objects (e.g., dynamically created StringIO instances), and so on. Here is the documentation.

    However, I will note that on a high-volume site, the best practice is to put static files on another server behind apache et al, or at least on the same server but behind apache, etc.

    Finally, you can get very dynamic with cherrpy by letting part of the URL be an argument to your Python method.

    For example, you can write a method like this:

    def photos(self, name):
    # serve the photo named `name`

    And then have URLs like:


    And so on.

  • Adnan

    aah!! This is exactly wht I wanted… Thanks very much!

  • ZhangLihua

    Hey Ryan, thanks very much for the post.
    Unfortunately, though I did exactly what you have post, I just can’t get the right ajax result. after filling in the name and clicking Set, my page did not change at all.
    I’m so confused about ajax with cherrypy. could you help me..thanks so much.

  • Raul Simcic

    Hi Ryan,

    can You please help me with something. How can I modify your example and send some data (let’s say an integer value) to the web page from cherrypy web server for example every 60 seconds without pressing any submit or other button?


  • If you’re using Ubuntu 15.04 and Python 2.x then don’t install CherryPy 2.3.0-4 via `sudo apt-get install python-cherrypy` because it will give you this error: `AttributeError: ‘module’ object has no attribute ‘engine’`. If you install CherryPy 3.8.0 via `sudo pip install cherrypy` it will work just fine, however.

    As for Python 3.x on Ubuntu, it doesn’t matter whether you use `sudo pip3 install cherrypy` or `sudo apt-get install python3-cherrpy3`. However, you’ll find that the above code doesn’t work on Python 3.x. All you need to do is edit line 25 and it will work. Replace `return simplejson.dumps(dict(title=”Hello, %s” % name))` with `return simplejson.dumps(dict(title=”Hello, %s” % name)).encode()`, because it needs to return bytes in Python 3.x. It still seems to work in Python 2.x if you have that `encode()` method on the end of that line, too. Anyway, without `encode()` you get errors about how you need to use tools.encode and such (I believe in your config variable). I first tried adding `’tools.encode.on’: True,` and `’tools.encode.encoding’: ‘utf-8’` to the config variable, but it had no effect, and apparently, it’s not required for our purposes, it seems. Feel free to tell me if that’s important to have anyway for other contexts we might encounter here.

Leave a Reply




You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>