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:

ajax_app.py
media/
  + jquery-1.4.2.min.js
  | index.html

First, I'll show the HTML file:

<html>
<head>
    <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 ;
        });
    });
</script>
</head>
    <body>
    <h1 id="title">What's your name?</h1>

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

        <input type="submit" value="Set" />
        </p>
    </form>
    </body>
</html>

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.

jQuery.post 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 ajax_app.py file:

import cherrypy
import webbrowser
import os
import simplejson
import sys

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

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

    @cherrypy.expose
    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():
    webbrowser.open("http://127.0.0.1:8080/")
cherrypy.engine.subscribe('start', open_page)
cherrypy.tree.mount(AjaxApp(), '/', config=config)
cherrypy.engine.start()

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():
    webbrowser.open("http://127.0.0.1:8080/")
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 ajax_app.py, 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.

14 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, http://10.1.5.221:8080) instead of using 127.0.0.1

    But I’m not able to do a GET from 10.1.5.221:8080

    Thoughts?

  • Nicholas: You need to modify the config like this

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

  • Adnan

    Hi..
    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):
        @cherrypy.expose
        def index(self):
            return open(os.path.join(MEDIA_DIR, u'index.html'))
        @cherrypy.expose
        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:

    /photos/sandy
    /photos/pat
    /photos/andy

    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?

    thanks

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=""> <strike> <strong>