Using Python to build a web project using jQuery (AJAX) and Flask

Post to Twitter

I’m working on a new project where I need to have a dashboard fetch updates on a regular basis from it’s host server. I decided to use Flask which is a microframework for Python based on Werkzeug and Jinja 2 (a template engine). Today I’ll show you a simple project to have a webpage communicate to the server via AJAX using jQuery.


The Flask documentation has a very simple example of how you can use Flask:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

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

Even if you don’t know Python very well this code shouldn’t be too difficult to understand. One route gets setup which if you hit the endpoint with a browser or cURL you will get the text Hello World returned back to you.

I’m going to be using Virtualenv for Python. If you don’t have it installed I would recommend you do so. Virtualenv has several good things about it and one of which is it keeps third party modules out of your global Python library so you can focus on a particular version of a library without polluting other Python projects. In a nutshell, Virtualenv creates isolated Python environments on your system. Another benefit is you can do installs without having to resort to sudo.

Assuming Virtualenv is installed and working go ahead and create a Virtualenv folder and install Flask. Here are the command line steps I used:

$ virtualenv flaskajax
$ cd flaskajax
$ source bin/activate
$ pip install flask

Let’s take that initial code an modify it to serve a webpage and to listen for incoming AJAX requests.

flaskdemo.py:

from flask import Flask, jsonify, render_template, request
app = Flask(__name__)

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/echo/', methods=['GET'])
def echo():
    ret_data = {"value": request.args.get('echoValue')}
    return jsonify(ret_data)

if __name__ == '__main__':
    app.run(port=8080, debug=True)

Create a templates folder and add two files to it: index.html and layout.html

Inside the layout.html file add the following code:

<!doctype html>
<html lang="en">
    <head>
        <title>Flask AJAX Demo</title>
        <meta http-equiv="content-type" content="text/html; charset=utf-8">
        <script type=text/javascript
          src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
        <script type=text/javascript>
          var $SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
        </script>        
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
</html>

Inside the index.html file add the following code:

{% extends "layout.html" %}
{% block content %}
<script type=text/javascript>
  $(function() {
    $("#submitBtn").click(function() {
         $.ajax({
            type: "GET",
            url: $SCRIPT_ROOT + "/echo/",
            contentType: "application/json; charset=utf-8",
            data: { echoValue: $('input[name="echoText"]').val() },
            success: function(data) {
                $('#echoResult').text(data.value);
            }
        });     
    });
  });
</script>
<strong>Enter a value to echo back:</strong>
<input type='text' size='10' id='echoText' name='echoText'>
<button type='button' id='submitBtn' name='submitBtn'>Submit via AJAX</button><br /><br />
<strong><div id='echoResult'></div></strong>
{% endblock %}

Run the Python code and load the webpage in a browser and then put something in the textbox to see it get echoed back. You may have also noticed that I added debug=True in the start-up for the app. This will ensure the latest Python code in flaskdemo.py is automatically reloaded when a file change is detected.

Now let’s add a little code to ensure that the client is actually sending a content-type of application/json. You can do this by adding the following:

@app.before_request
def before_request():
    if request.path != '/':
        if request.headers['content-type'].find('application/json'):
            return 'Unsupported Media Type', 415

This as you can probably tell will run before the actual dispatch to the /echo/ handler.

The flaskdemo.py should now look like this:

from flask import Flask, jsonify, render_template, request
app = Flask(__name__)

@app.before_request
def before_request():
    if request.path != '/':
        if request.headers['content-type'].find('application/json'):
            return 'Unsupported Media Type', 415

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/echo/', methods=['GET'])
def echo():
    ret_data = {"value": request.args.get('echoValue')}
    return jsonify(ret_data)

if __name__ == '__main__':
    app.run(port=8080, debug=True)

So if they are not calling the root entry point we verify that the content-type is JSON, however, you should verify in your application whether or not the incoming payload is actually valid JSON and not trust the content-type. If the content-type is not set to application/json then we return an HTTP 415 code (unsupported media type).

Modify the index.html JavaScript to send a different content-type, perhaps something like this:

contentType: "application/xml; charset=utf-8"

The index.html file should look like this (also includes some error handling to catch the HTTP 415:

{% extends "layout.html" %}
{% block content %}
<script type=text/javascript>
  $(function() {
    $("#submitBtn").click(function() {
         $.ajax({
            type: "GET",
            url: $SCRIPT_ROOT + "/echo/",
            contentType: "application/xml; charset=utf-8",
            data: { echoValue: $('input[name="echoText"]').val() },
            success: function(data) {
                $('#echoResult').text(data.value);
            },
            error: function(jqXHR, textStatus, errorThrown) {
                alert(errorThrown);
            }
        });     
    });
  });
</script>
<strong>Enter a value to echo back:</strong>
<input type='text' size='10' id='echoText' name='echoText'>
<button type='button' id='submitBtn' name='submitBtn'>Submit via AJAX</button><br /><br />
<strong><div id='echoResult'></div></strong>
{% endblock %}

Try out the new code (make sure to refresh the browser so that latest HTML is loaded).

Post to Twitter

This entry was posted in JavaScript, Open Source, Python. Bookmark the permalink.

One Response to Using Python to build a web project using jQuery (AJAX) and Flask

  1. bobbice says:

    Best demo. of linking Ajax to Python server ( and app).
    Start with the HTTP server, then template the client html, ONLY then try out the scripts =Perfect !
    This worked for me on initial copy! No more tutorials drowning in script and
    ending with the infamous ” $.get(‘somewhereovertherainbow.php’, ….) ”
    The Flask framework is perfect for development like this.
    thank you, Bob

Comments are closed.