Building a Python Web Application, Part 1

Edit: I’ve cleaned up the longer example, using Python’s string.Template module for the templates. I’ve also set up a git repo for the source that will go along with posts to this series: Python Webapp Gitweb

Recently, I’ve been interested in writing web applications in Python, and one of the fun things that I discovered was the Python Web Server Gateway Interface, which is a standard interface for Python web servers, web applications, and something called middleware which can sit between the two.

One of the coolest things about WSGI is the fact that you now don’t have to decide on a specific web server before you start coding. In fact, the Python wsgiref module comes with a built-in simple web server which allows you to start coding up your web application with nothing but a bare install of Python 2.5 (or higher, of course)!

There are plenty of overviews of WSGI out there, so I won’t bother creating yet another in-depth explanation. What I will do, though, is show you how easy it is to get started.

Your basic “Hello, World!” application can be accomplished, server and all, with as little as the following:

def handle_request(environment, start_response):
    start_response(‘200 OK’, [(‘content-type’, ‘text/html’)])
    return [‘Hello, World!’]

if __name__ == ‘__main__’:
    from wsgiref import simple_server
    simple_server.make_server(, 8080, handle_request).serve_forever()

So what’s going on there is that the simple_server passes each request to the handle_request function, which calls start_response with the HTTP status code and a list of tuples of header names and values.

Then, an iterable is returned. This iterable will be iterated through for the output to send to the browser. In more complex applications, this iterable would most likely be a generator or some sort (a function which yields values or a generator expression, perhaps), rather than simply putting the entire output into a list.

The environment parameter contains all the information that any regular web application might need such as request information, server information, and any extra values set up by previously run middleware.

Using the basics we have from above, and a couple of nice utility functions from wsgiref.util, it’s a simple step to add a bit more and make this a full-fledged mini-framework.

from wsgiref import util
from string import Template

# Templates
wrapper = Template("""
<html><head><title>$title</title></head><body>
$body
</body></html>
"
"")

four_oh_four = Template("""
<html><body>
  <h1>404-ed!</h1>
  The requested URL <i>$url</i> was not found.
</body></html>"
"")

# Template Variables for each page
pages = {
    ‘index’: { ‘title’: "Hello There",
               ‘body’:  
               """This is a test of the WSGI system.
                Perhaps you would also be interested in
                <a href="
this_page">this page</a>?"""
              },
    ‘this_page’: { ‘title’: "You’re at this page",
                   ‘body’:
                   """Hey, you’re at this page.
                   <a href="
/">Go back</a>?"""
                   }
    }

def handle_request(environment, start_response):
    try:
        fn = util.shift_path_info(environment)
        if not fn:
            fn = ‘index’
        response = wrapper.substitute(**pages[fn])
        start_response(‘200 OK’, [(‘content-type’, ‘text/html’)])
    except:
        start_response(‘404 Not Found’, [(‘content-type’, ‘text/html’)])
        response = four_oh_four.substitute(url=util.request_url(environ))
    return [response]

if __name__ == ‘__main__’:
    from wsgiref import simple_server

    print("Starting server on port 8080…")
    try:
        simple_server.make_server(, 8080, handle_request).serve_forever()
    except KeyboardInterrupt:
        print("Ctrl-C caught, Server exiting…")

This now handles different URLs by rendering the wrapper template with the variables from the corresponding item in the pages dict, or it sends a 404 page if the requested page doesn’t exist (or if there are any other exceptions, actually).

With the addition of a templating engine and some way to get at your data, this would be something resembling a real web application.

For now, that’s all you’re getting out of me, though. I’ve shown that it’s pretty easy to get started with Python web development without anything but plain-ol-Python at your disposal, putting off choices on things like what server to use so you can get to the important part of actually writing some code. I’ll probably do another post in the next few days, probably starting to use some third-party packages to really start developing something useful.

Until then, if you want some more, see the WSGI tutorials at the link I posted above, especially A Do-It-Yourself Framework, which gives you a bunch more information of parsing requests, sending response headers, and using middleware. Keep in mind that some of the code there is Paste-specific, not that that is a bad thing. Since Paste is intended to be fairly lightweight it won’t really limit your options if you use it, and it doesn’t make sense to write a whole bunch of code to do the mundane parts from scratch anyway.

Tags: , ,

22 Responses to “Building a Python Web Application, Part 1”

  1. Timmy Jose Says:

    Mate, your site is totally messed up in Opera!

  2. Andreas Schipplock Says:

    ehm…ya…/* no comment */ ;).

  3. Max Says:

    No No No .. just download web2py and type:

    def index(): 
        response.title="Hello There"
        return dict(message=P("""This is a test of the WSGI system.
                    Perhaps you would also be interested in""",
                    A("this page",_href="this_page"),"?"))
    
    def this_page():
        response.title="This Page"
        return dict(message=P("""Hey, you’re at this page.""",A("Go back",_href="index")))
    
  4. James Says:

    Your blog is also completely messed up in Safari.

  5. pib Says:

    @Timmy: I’ll have to take a look at that, I’ve not tested it with Opera at all.

    @Andreas: Yeah, I suppose I didn’t put any comments in there, I guess I’ll go back in and add some. Oh, and that should’be been # no comment ;)

    @Max: Well, yes, if this had been “Building a Python Web Application using web2py”, but it’s not. The idea was to show that you can do it fairly easily without having to download any third-party applications. Also, that doesn’t seem to be a complete example, where’s the WSGI in that and where does it actually start serving things up? Your example is not a standalone web application, mine is. :P

  6. pib Says:

    @James: Uggh, I suppose I need to look at my site in browsers other than Firefox, eh?

  7. dude Says:

    Thanks for this article, nice easy intro to wsgi.

    I also have to note: Ignore Max, web2py blows long and hard.

  8. jim Says:

    Page also laid out incorrectly in IE7…

  9. miles Says:

    Nicely written article. Hope the series continues.

  10. gilzow Says:

    @pib: Actually, I think Andreas meant “”" no comment “”"

  11. me yeah me Says:

    Using opera 9.50 and it looks fine to me.

  12. israel Says:

    Dude, nice article. Pd. Your site looks messy in Safari 3.1 on Leopard.

  13. Max Says:

    pib, I agree. Your article is in fact quite excellent. The problem I see is that while Python is an excellent language for web development (because of wsgi) most of the examples posted out there scare non-python programmers away, they are too low level. This is the point I tried to make with my comment and with my work. I do not think we should encourage people to program at this low level because they may create very insecure applications (no url validation, no input validation, no secure cookies, no escaping of output, etc.) Python may get the same bad reputation as PHP does. We need to encourage people to use a high level framework (web2py or Django or TurboGears, etc.) that will give access to the power of python but that will take care of many issues for them. There is no progress if we all start from scratch. There is progress we all “stand of the shoulders of giants”.

  14. The Burgeoning Openly Owned Web » links for 2008-06-28 Says:

    [...] PIBlog » Blog Archive » Building a Python Web Application, Part 1 (tags: python webdev wsgi webapp) [...]

  15. pib Says:

    @Max: I agree that starting completely from scratch is probably not a good idea. However, I wouldn’t say that we need to encourage people to use high-level frameworks. Or at least, we don’t need to encourage people to use entire high-level frameworks.

    That’s the nice thing about wsgi, you can take bits and pieces from all over the place and glue them together with relatively little effort.

    Unless you’re creating an application which fits perfectly into the model of a given framework, it will probably take you less time to make your own framwork which matches your needs exactly. Not from scratch, but from existing standalone pieces. Otherwise, you’ll end up spending a large chunk of time working around quirks in the framwork you’ve chosen, or even worse, you’ll find yourself locked into a given framework even when it proves to not fit as well as another would.

    This is especially bad when you run into issues of scalability. If you make your application out of loosely coupled components, you can easily swap out the chunk that doesn’t scale well. With some framworks, this (swapping out bits and pieces) can be difficult to do.

    In my next post on this subject I’ll be going into more detail of using preexisting components to build you own application, so you’ll see I’m not advocating building a whole application at such a low level. This starting post was just to give an idea of what will lie below everything.

  16. links for 2008-06-28 « Donghai Ma Says:

    [...] PIBlog » Blog Archive » Building a Python Web Application, Part 1 (tags: python webdev programming wsgi webapp web) [...]

  17. Max Says:

    Pid, it depends on the goal. If the goal is to develop simple web applications than it is fine to take bits and pieces from different sources. I personally do not think there is much progress this way. I think we need few stable frameworks so that wen start developing complex plugins and specifications so that we can start programming at an even higher layer that any of us do know. Let’s say I see a web app that has a nice widget. I want to be able to get the widget (literally grab it from the web page) and paste it into my app and it should just work. We’ll never get there if people we continue bottom-up development. web2py API have been frozen for 8 months (we only add features and fix bugs, but never break backward compatibility) because we going to move to the next level.

  18. pib Says:

    I would also say that it’s not just if the goal is to develop simple web applications.

    Another perfectly acceptable reason is education.

    By developing my own fairly complete (albeit simple) framework, I can better understand how things work at a lower level. This will, among other things, help me to make a good decision about what framework to use for more complex applications.

  19. rascunho » Blog Archive » links for 2008-06-29 Says:

    [...] PIBlog » Blog Archive » Building a Python Web Application, Part 1 Recently, I’ve been interested in writing web applications in Python, and one of the fun things that I discovered was the Python Web Server Gateway Interface, which is a standard interface for Python web servers, web applications, and something called m (tags: blog.paulbonser.com 2008 mes5 dia28 at_home Python web blog_post) [...]

  20. Programando una aplicación web con Python Says:

    [...] más en: Building a Python Web Application, Part 1. Archivado en Diseño Web, Miniblog, Programación Deja aquí tu comentario ↓ [...]

  21. links for 2008-07-08 « Bloggitation Says:

    [...] Building a Python Web Application, Part 1 (tags: python web wsgi programming blog) [...]

  22. frank Says:

    One odd thing, to stop the server (at least under Windows) I have to press Ctrl-C and reload a page before the server loop will exit. This is the same behavior that you see under Google’s AppEngine; maybe they are both using simple_server, I haven’t checked.

Leave a Reply

What I'm Listening to

Loading...