Archive for the ‘jQuery’ Tag

Python and AJAX tutorial for beginners with web.py and jQuery

Note: I’m always surprised to see this at the top of a Google search for ‘ajax python’. It has been three and a half years after all (though I guess that’s how these things work sometimes). I haven’t been following the state of Python web development at all, so this code may be badly out-of-date, simply not work, etcetera. If you’re just starting out on your Pythonic path, I feel like my best recommendation is to Google on, my friend, Google on…

– George
14 September, 2013

As a result of following along with the NYU class Reading and Writing Electronic Text I started to get into using Python for web apps — this, along with learning JavaScript, is something I’d been wanting to do for a while.

I’ll try to summarize what I’ve learned over the last week or so. What I was looking for was a simple way to get into this stuff, and as I discovered it’s not so simple, for a hobbyist like myself, once you combine two or three frameworks in a project. Maybe this post will help someone else in the same situation.

Python already was the choice for the server-side script. What I then needed was a way for the browser to communicate with the script. There are literally dozens of ways to do this, and the Python wiki has a good page on web programming. I also found this conversation springing from a post by the BDFL at Artima a good read, though it’s a few years old now.

I decided to keep it simple (though I still want to learn frameworks like Django, TurboGears, etcetera at some point in the future). I considered looking into using CGI with Python, but then I found web.py, a lightweight web framework, and liked it immediately.

The web.py framework can run its own basic web server or interface with others such as Apache or lighttpd. It includes a simple HTML template language that basically is just HTML + Python. It works with databases or not. In short it has all you need to get things running quickly.

So I had the server language and the web framework. All that remained was the client-side. Rather than rolling all the JavaScript myself I went with the jQuery library. I had heard some good things and it looked good when I checked it out.

OK, first let’s look at the basic project structure. Note that I’m using web.py’s templates, though this isn’t required:

- webpy_jquery_ajax_tutorial
  - static
      jquery.js
     tutorial.css

  - templates
    tutorial.html
  app.py

Within the project directory we include the static and templates directories (required terms for web.py). Files such as CSS, JavaScript, images, and so on are put in static. HTML templates go in templates, and everything else can go in the main project directory.

Our app.py is the web.py script that controls our app. It looks like this:

import web

def make_text(string):
    return string

urls = ('/', 'tutorial')
render = web.template.render('templates/')

app = web.application(urls, globals())

my_form = web.form.Form(
                web.form.Textbox('', class_='textfield', id='textfield'),
                )

class tutorial:
    def GET(self):
        form = my_form()
        return render.tutorial(form, "Your text goes here.")
        
    def POST(self):
        form = my_form()
        form.validates()
        s = form.value['textfield']
        return make_text(s)

if __name__ == '__main__':
    app.run()

Other than the simple echo function defined for this tutorial, there are some critical parts to the code above, so let’s look at it more closely.

First of all web.py will map the URL to classes in the script. That’s why we have urls = (‘/’, ‘tutorial’), which says map the root URL address to what happens in the tutorial class defined later.

Second, if we’re using templates we tell web.py where to find our HTML templates with render = web.template.render(‘templates/’). The my_form creates an HTML text entry box that we’ll render later. We give it an empty string for a name simply for aesthetic reasons (otherwise you’ll see it on the HTML page).

Finally we define the tutorial class. We create the GET and POST methods ( web.py intentionally requires this)to define the behaviour of our web.py app in response to browser client requests. Looking at GET:

    def GET(self):
        form = my_form()
        return render.tutorial(form, "Your text goes here.")

Defining form = my_form() gives us a copy of the form instance we created earlier. The method render.tutorial() returns a rendering of the tutorial HTML template (using the same name tutorial here in the class definition, the call, and eventually the HTML template are important here!), passing the arguments form and the text string to the template at the same time.

Now for POST:

    def POST(self):
        form = my_form()
        form.validates()
        s = form.value['textfield']
        return make_text(s)

Again using a copy of the form instance, we automatically validate it (simply because I haven’t learned how to validate forms yet!). We can then access the value of our textfield box with form.value['textfield'], and send it to our echo function defined earlier.

That’s all you need in the app.py, now to look at the HTML template (located in the templates directory):

$def with (form, text)

<!doctype html>

<html>

    <head>
        <title>Hello</title>
        <link rel="stylesheet" type="text/css" href="/static/tutorial.css" />
        
        <script type="text/javascript" src="/static/jquery.js"></script>
        
        <script type="text/javascript">
                                jQuery(document).ready(function() {
                                jQuery(".button").click(function() {
                                        var input_string = $$("input#textfield").val();
                                        jQuery.ajax({
                                                type: "POST",
                                                data: {textfield : input_string},
                                                success: function(data) {
                                                jQuery('#foo').html(data).hide().fadeIn(1500);
                                                },
                                                });
                                        return false;
                                        });
                                });
        
                        </script>
    </head>
    
    <body>
        <br>
        <form class="form" method="post"> 
        $:form.render()
        <input class="button" type="submit" value="send"/>    
        </form>

        <br><br>
        <span id="foo">$text</span>        
    </body>
    
</html>

(we’ll see how WP handles the syntax styling with that…)

There’s a little more going on here so let’s take it one step at a time.

In a web.py template the first line of the file defines what data is passed to the template by web.py. So here we have $def with (form, text), which as you’ll recall parallels the call we made in the GET method above. So when a client requests this page, those arguments are passed along.

The web.py templating language uses ‘$’ symbols to denote Python expressions (and the arguments passed into the template). To use an actual ‘$’ just escape it with ‘$$’. Note that it’s a popular habit in jQuery to also use the dollar sign to mean the jQuery object, but we can get around that conflict simply by using ‘jQuery’ instead in the JavaScript. There are other ways around that but I like this method for its simplicity and how it feels the same as Python namespaces.

The head tag of the file is nothing special, it just tells us where the CSS and .js files are located (though it’s important to web.py that they’re in static as explained before). The JavaScript that follows needs some more explanation though:

        
        <script type="text/javascript">
                                jQuery(document).ready(function() {
                                jQuery(".button").click(function() {
                                        var input_string = $$("input#textfield").val();
                                        jQuery.ajax({
                                                type: "POST",
                                                data: {textfield : input_string},
                                                success: function(data) {
                                                jQuery('#foo').html(data).hide().fadeIn(1500);
                                                },
                                                });
                                        return false;
                                        });
                                });
        
                        </script>

It’s actually pretty simple. All this does is send what’s in the textfield box to the server when the button is clicked. If the action is successful (i.e. the server accepts the input data and returns it OK), jQuery replaces what’s in the foo element with the data returned. This uses the ajax() function — so the page doesn’t reload (it’s not really AJAX as you may realize, since there’s no XML exchanged — that’s OK, I don’t like XML anyway! ;) )

I’ll point out some conventions that a beginner should know. Saying “.button” just refers to the element with the button class (defined in our app.py script, look above). Saying “input#textfield” refers to the input element with the CSS id of textfield (also defined in app.py).

The success function passed through ajax() is called if the action is successful; the part with hide() and then fadeIn() is just a prettier way of displaying the new text on the HTML page (otherwise, it just replaces it with no transition effect).

Lastly, returning false prevents the page from reloading.

Moving on to the body of the HTML page:

    <body>
        <br>
        <form class="form" method="post"> 
        $:form.render()
        <input class="button" type="submit" value="send"/>    
        </form>

        <br><br>
        <span id="foo">$text</span>        
    </body>
    

All we do here is enclose a rendering of the textfield and button in form tags. This isn’t totally necessary, but as I discovered, without the form tags pressing return in the textfield box doesn’t activate the button (i.e. you have to click on the button). Apparently you can process keyboard events with jQuery but this seemed simpler.

An additional note about $ is that you need to use $: if the expression will contain some HTML that you don’t want escaped, as we do with $:form.render.

The foo span element is just a basic container that the jQuery function can replace with the new text.

To recap, what this does is display (from your browser GETting the page from the server) a HTML page with a textfield and button. When you enter text in the textfield and submit it (that is, POST it), the JavaScript on the HTML page runs, and replaces the foo element with the text processed and returned by the app.py without reloading the page. There you have it — basic Python and AJAX!

There are some obvious improvements to be made here. First of all there’s nothing stopping the user from clicking the button multiple times and sending multiple POST requests (probably not a desirable situation). There also isn’t any user session setup or form validation. In any case these things are next in my list to learn, but my experience with web.py and jQuery has been great so far. I’m looking forward to more!

Also, the documentation for web.py and jQuery are good, so check those out for more information on their APIs.

I’d like to thank the members of the web.py mailing list, particularly Branko Vukelić, for their feedback on an earlier draft of this post. Naturally all errors are (most definitely) my own.

If you’d like a zipped copy of the files in this tutorial, you can get it here. Run app.py and then point your browser to http://localhost:8080 (on Windows; use the appropriate address for your setup).

Follow

Get every new post delivered to your Inbox.