Playing around with Django

Recently I have been messing around with Django, a very cool Python powered web framework that makes it very easy to create websites quickly. Like similar frameworks (i.e. Ruby on Rails, CakePHP, etc.) Django excels at doing most of the heavy lifting for you. What is most jarring at first, and perhaps the most powerful design choice later on, is that Django has an almost complete separation of server side code from website design.

How does it work?

Django works in a very straightforward way.

  1. Upon receiving a new request, Django will match the request to a handler function.
  2. The handler function will gather all of the data needed to display the page as well as do any server-side changes (i.e. database updates or whatever).
  3. The handler function will pass the information to the HTML template to render and the result will be sent back to the requester.

This very straight forward, three step process is just a high level view of the power that Django offers however.

1. Match incoming requests to an appropriate handler function

This step is actually done by using Django’s urlpatterns system. Essentially a collection of regex this (very fast!) function easily re-directs your incoming requests to their destinations. For instance in the example below a request to www.example.com/ would be handled by the index_handler function, whereas a request to www.example.com/hello/ would be handled by some_other_function.

urlpatterns = patterns('',
     ('^/$', index_handler),
     ('^hello/$',  some_other_function),
)

What’s beautiful about this is that you can easily change the URL structure of your website (or just change URL mappings) without actually moving any code. So unlike something like classical PHP, where the code is embedded in the web page, Django simply looks at the incoming URL and then decides which code it should run. If I want to change my URL syntax from www.example.com/blog/ to www.example.com/awesomeblog/ I can do it (without breaking anything!) by just changing this file. And this is just the start of the cool things you can do with this file. As the official Django tutorial says:

Because the URL patterns are regular expressions, there really is no limit on what you can do with them. And there’s no need to add URL cruft such as .php — unless you have a sick sense of humor, in which case you can do something like this:

(r’^polls/latest\.php$’, ‘polls.views.index’),

But, don’t do that. It’s silly.

2. The handler function

Instead of reinventing the wheel, each handler function is simply a standard Python function that takes in a request object. In its most basic form it looks something like this:

def hello(request):
     return HttpResponse("Hello world")

Of course being standard Python these functions also inherit the ability to do anything Python can do, including using real objects. Django does an excellent job of marrying these objects with the database engine so that, if you want to, you don’t ever have to write any real SQL. Instead Django will handle the creation of highly optimized SQL calls for you automatically when you call basic object functions.

One of the coolest built in features is the Form class. This class represents a standard HTML form as well as a selection of standard rendering formats (i.e. tables, ordered lists, unordered lists, etc.) in addition to allowing you to completely customize them. Why put this HTML in a Python function and not in the HTML template? Because using it here gives us free validation. I’ll give you an example:

class ContactForm(forms.Form):
     subject = forms.CharField()
     email = forms.EmailField(required=False)
     message = forms.CharField()

Creates a form class with three fields (two of which are required). The resulting HTML (depending on how you want it displayed) is something like:

<tr><th><label for="id_subject">Subject:</label></th><td><input type="text" name="subject" id="id_subject" /></td></tr>
<tr><th><label for="id_email">Email:</label></th><td><input type="text" name="email" id="id_email" /></td></tr>
<tr><th><label for="id_message">Message:</label></th><td><input type="text" name="message" id="id_message" /></td></tr>

OK so how is it used?

def contact(request):
     if request.method == 'POST':
          form = ContactForm(request.POST)
          if form.is_valid():
               return HttpResponse("Everything was valid!")
          else:
               form = ContactForm()
               return render_to_response('contact_form.html', {'form': form})

This function will accept the form’s submitted POST arguments, validate them (meaning that at a minimum the subject and message fields need to be filled out) and return a page saying “Everything was valid!”. If the form is not valid it simply hands off the form object to the template engine to be rendered into the html file called “contact_form.html”

3. The template engine

Sticking to its MVC roots Django makes it very easy for web designers to use the data they need without actually needing to write any real code.

For instance here is the example contact_form.html from above:

<html>
  <head>
    <title>Contact us</title>
  </head>
  <body>
    <h1>Contact us</h1>
    <form action="" method="post">
      <table>
        {{ form.as_table }}
      </table>
      <input type="submit" value="Submit">
    </form>
  </body>
</html>

The {{ }} braces tell the temple engine to place a Python object in the page at that spot. This is great but what if you need to handle multiple pieces of data (like a Python list)? The template engine allows you access to easy functionality to accomplish anything you can think of. Here is an example of some template ‘code’ that will put all of the items in item_list in an unordered HTML list for displaying.

<ul>
  {% for item in item_list %}
    <li>{{ item }}</li>
  {% endfor %}
</ul>

More to come

I know this post sounds a lot like an advertisement but the truth is that the flexibility and power of Django is really stunning. I will definitely be doing some more work in this framework going forward so expect to see more updates sometime in the future.

Useful links: