BlogMatrix
 

Playing with Django

edit David P. Janes 2008-06-16 11:30 UTC add comment  ·

Here's a few notes I made while working my way through Django's tutuorial:

Installation

Installation of Django is easy. Just following the instructions on this page:

It can either be downloaded as a tarball or via SVN. We've chosen the tarball (0.92.2) option.

Nitpicking, the tarball URL doesn't end with the name of the tarball - it's a directory. This is only slightly annoying.

Our environment has as per-user Python installation, so we don't need to use "sudo" to install the Django packages

Testing (Part 1)

We are following the instructions son this page:

Running a development webserver

Django has options for running under mod_python, WSGI or using a standalone built in webserver. The built-in webserver is documented as not-for-production, but it's good enough to get going so we're going to play with that for now. Eventually we expect to use both the mod_python (because we have it here) and WSGI options (because it's both the way to go and the most efficient).

We immediately ran into issues running the webserver because it's not on the "localhost" - the browser said it couldn't find the server. In our environment we ssh to a linux server and access that from our desktop computer. After a little googling, the trick turns out to be adding a "IP:port" argument to the Python command:

python manage.py runserver 192.168.1.10:8000

Connecting to the DB

Next in the instructions is connecting to the DB. Again, we have issues here - no fault of Django - because of the uniqueness of the local environment. Like Python we run MySQL on a per-user basis so we need to be able to specify a fairly unique setup with a TCP/IP and UNIX domain socket. It's not clear initially how to specify the path for the UNIX domain socket but fortunately the stack traceback and clearly written code come to our rescue here: you use the DATABASE_HOST and the code looks to see if it's a path.

Creating the DBs

The ‘syncdb' asked if I'd like to create a super user for the DB. I said no and everything seems to be working - a bunch of tables show up in MySQL as promised.

Creating an App

An "app" is something that does something or something like that. The command works as promised.

Create the Model and DB tables

Works as promised. There appears to be some underlying cleverness happening as (for example) the "sqlclear" command knows whether the tables are their or not.

The "sqlinitialdata" refers you to another command; this is probably a mismatch between the code and the tutorial.

Interactive Shell

This is cute - running "python manage.py shell" will drop you in the environment that the webserver sees so you can do stuff on the command line to see how it will work.

Stylistically, I differ from Django in that I (almost) never do anything except ‘import x', as I prefer to use the dotpath and not have to guess when I'm skimming code as to where functions are coming from.

As an aside, it would be cool if Python examples did the ‘>>>' as an image or as an CSS trick so they don't get copied when cut-and-pasting examples.

Testing (Part 2)

And we're on to page 2 of the tutorial:

Admin Interface

And we get our first "uh oh" - we didn't create a "superuser account" on way back above, well, just because. Fortunately, Lord Google knows all and we quickly find out that you can run Python commands to do this and we're in business:

$ python manage.py shell
>>> from django.contrib.auth.create_superuser import createsuperuser
>>> createsuperuser()


Thanks to here for the tip (which also looks like interesting reading):

Admining the App

Nice - add an inner class declaration to App "Poll" and it now shows up in the Admin interface and we can do stuff with it. Neato.

I've also just discovered that I don't need to stop and restart the app - it's using reload().

Adding __str__ to the model makes the Admin app useful; if you do something wrong the HTML function is really quite clear.

You can change the way the Admin interface displays Poll by adding a ‘fields' declaration. This is a little bizarre - it's a tuple, of tuples with a dictionary inside. Why not a list of dictionaries?

Bug: if you use the ‘classes/collapse' option of the admin interface and there's a bug while saving an item while the item is collapsed, there's no indication of where the error is.

Changing Templates

The instructions are a little confusing - pay attention - but it works as advertised. There's a command called ‘adminindex' which dumps out template code but I'm somewhat confused by it and I wish there was a little more detail here.

Testing (Part 3)

And we're on to page 2 of the tutorial.

Design your URLs

Django converts URLs coming from user requests into actions by:

  • looking at ROOT_URLCONF in settings.py
  • loading mysite/urls.py (as defined in the settings)
  • sequentially looking at regular expressions
  • loading a module - typically a view - and calling a function defined by the matching regular expression. This is expressed as a dotpath - e.g. ‘x.y.z' will load module ‘x.y' and call function ‘z'
    • the function is called with a request object and all the named groups from the regular expression - clever
  • also note that:
    • you cannot filter on the hostname in the URL (problem?)
    • regular expressions are compiled (and thus are very fast)

The code samples work as advertised. In a later section we'll learn that you can move all the URLs into the app so that you don't have to (a) put all the URL information at the project level (b) decouple the base path of the URL being used.

Write views that do something

This section explains how to returning meaningful results building on the knowledge in section 2.

  • the template loading system rocks
  • the shortcuts are very handy (i.e. lots of common actions are compressed into single function calls)

Playing with forms (Part 4)

This section is a mess. I'll probably retackle it.

Something I'd like to see in the Cheetah Template language

edit David P. Janes 2006-09-28 11:14 UTC add comment  ·  ·

All the pages you see here are produced by the Cheetah template language. We're pretty happy with it, though it looks to some degree that the world is standardizing around Django's competing package.

There is one lovely feature of Django that I'd like to see in Cheetah -- the ability to know where you are in a for loop:

forloop.counter The current iteration of the loop (1-indexed)
forloop.counter0 The current iteration of the loop (0-indexed)
forloop.revcounter The number of iterations from the end of the loop (1-indexed)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed)
forloop.first True if this is the first time through the loop
forloop.last True if this is the last time through the loop
forloop.parentloop For nested loops, this is the loop "above" the current one

Cheetah requires the decidely unlovely formulation of this ...

#set $sep = '' 
#for $name in $names
$sep$name
#set $sep = ', '
#end for

... to make a comma seperated list of names (I know about the other way for trivial lists, this is an example for illustration). I'd much rather do:

#for $name in $names 
$name
#if $forloop.is_last then "" #else ","#
#end for

Or even (thinking more):

#for $name in $names 
$name
$forloop.if_not_last(",")
#end for 

At some point we may try template translation tricks, not only (or possibly) to move Cheetah to Django templates (if they are seperable from the platform) but also to covert MovableType and Blogger templates to our internal format.

Using Amazon S3 to serve static files

edit David P. Janes 2006-08-06 12:11 UTC 2 comments  ·  ·  ·  ·  ·

The V10 look and feel (i.e. what you're seeing here) uses a substantial number of GIF files to achieve the candy-like "web 2.0" look. Additionally since we're using a fair number of javascript include libraries (MochiKit, TinyMCE, Yahoo UI), what we're ending up is a lot of trips to our server the first time a user sees a page.

This equals unnecessary slowness and page response time. What I'd like to do is speed this up a little (or maybe a lot) by offloading serving these mostly static files. Right now I'm experimenting with Amazon S3 and I'll document what I'm doing.

I'm not breaking any ground here: Adrian Holovaty did this first to offload pages from Chicago Crime and has documented his experiences. I'm just going to expand and annotate what he wrote (the blockquoted italics text is his):

It was easy to get this working; took less than an hour total. Here's what I did:

First, I signed up for an Amazon S3 account. Do that by clicking "Sign Up For Web Service" on the main S3 page. When you sign up, you get two codes: an access key ID and secret access key.

You'll need to provide a credit card to pay for your (as-you-use-it) Amazon S3 services. You have to click on a provided link to get the keys. There's a X.509 certificate (rather than secret key) way of accessing your S3 account but it only works with SOAP and I'd rather stick a fork in my eye and wiggle it around first. Moving right along...

Next, I created an S3 "bucket" for my chicagocrime.org media files. An account can have multiple buckets. As far as I can tell, it's just a way of keeping your S3 stuff in separate containers. I did this by using the free S3 Python bindings. Just download the file, unzip it and put the file S3.py somewhere on your Python path. To create a bucket named 'mybucketname', do this:

import S3
conn = S3.AWSAuthConnection('your access key', 'your secret key')
conn.create_bucket('mybucketname')

I found it easier just to distutil S3.py into my standard Python library:

from distutils.core import setup
setup(
        name='S3',
        version='20060805',
        py_modules=['S3'],
)

I created a bucket called 'semantic.blogmatrix.com'

Next, I wrote a Python script that uploaded my media files to this bucket and made them publically readable. S3 has a bunch of complex authentication stuff, but all I wanted to do was use S3, essentially, as a Web hosting service. Here's the script I used, and here's how to use it:

cd /directory/with/media/files/



find | python /path/to/update_s3.py

The script is kind of cool because it uses Python's mimetypes to determine the content type of each file in order to pass that to the S3 API. Otherwise it's pretty straightforward.

I've written my own little program (attached) to do this which takes care of all the path searching, etc.. I'll probably modify it some more to track what it's uploaded so we don't multiple upload files. Here's the help:

blogmatrix.v10@s002. python S3Uploader.py --help
usage: S3Uploader.py [options]

options:
  -h, --help            show this help message and exit
  --debug              
  --bucket=BUCKET       Amazon S3 Bucket
  --access-key=ACCESS_KEY
                        Amazon S3 Access Key (required)
  --secret-key=SECRET_KEY
                        Amazon S3 Secret Access Key (command line prompt if
                        missing)
  --root=ROOT           All directories are made relative to this (optional)
                        root
  --directory=DIRECTORIES
                        Upload files from this directory (default: .)
  --extension=EXTENSIONS
                        Upload files matching this extension (default: all
                        files)

For example:

python S3Uploader.py \
--bucket semantic.blogmatrix.com \
--access-key 0ZB0XFMV5NE1KM15DKR2 \
--extension gif,jpg,png,css,js \
--directory v10/media \
--root ~/htdocs

Finally, it's a matter of plugging in the changed files. Adrian does it like this:

Finally, it was just a matter of changing my chicagocrime.org templates to point to S3's URLs rather than my own URLs. That was a snap, thanks to Django's template inheritance and includes.

We do it with Apache rules:

RewriteRule ^/:root/(silk_icons/.*.png)$        http://s3.amazonaws.com/semantic.blogmatrix.com/$1  [R,L]
RewriteRule ^/:root/(v10/media/.*)$             http://s3.amazonaws.com/semantic.blogmatrix.com/$1  [R,L]
RewriteRule ^/:root/((MochiKit|tinymce|yui)/.*)$                http://s3.amazonaws.com/semantic.blogmatrix.com/$1  [R,L]

 

You're seeing the result here. All the background graphics and external javscript libraries are coming from Amazon S3.

Attached Documents: