8 Reasons Why You Should Try Django

January 6, 2010

django

I have been using Python for quite a few years, but mostly for writing one off sysadmin scripts, command line utilities, and of course PyRadio. Most of my web development work has been done with PHP. The language gets a lot of bad press, some deserved and some not so much. I’ve had my own gripes, but all-in-all I’ve been fairly happy with PHP.

Several months ago, though, I thought I’d give Django a try, a python based web framework. I was completely blown away!  Compared to the PHP frameworks I’d worked with, such as Cake, it was just so much more of a pleasure to work with. So here are 8 reasons why you should give Django a try yourself if you haven’t already. You won’t be disappointed!

1. Great Documentation

The Django documentation is well written, extremely comprehensive, and up to date. The official documentation contains details API references, loads of relevant examples, and tutorials for those getting started. If that isn’t enough there’s also a whole book that’s available for free online.

2. It’s Python

The fact that it’s Python is a huge plus point for me. It’s a great language that doesn’t suffer from many of the well documented inconsistencies that PHP does, and includes some nice features such as decorators and first-class functions. Going back to PHP you soon start to miss the little things, such as the ability to assign multiple values at once, and the simplicity of slicing lists.

3. The ORM

Django’s object relational mapper completely abstracts away the database, meaning you don’t need to worry about your database schema or constructing SQL queries. If you’re using to writing SQL queries then the QuerySet API takes a little getting used to, but it’s really worth the effort. Projects like South make the ORM even more powerful, allowing you to make schema changes and data migrations automatically.

4. Built in Development Server

Where PHP really shines is on its ease of deployment. Setting up a local development server can be a bit of a pain though, especially if you’re working on several different sites. Django comes with a built in development server though, so you can be up and running within minutes! From your project’s root directory you just do

./manage.py runserver

and access your django website from http://localhost:8000 – awesome!

5. The Admin Interface

Django’s built-in admin interface is practically a full blown CMS, allowing you to add, delete or update your data. It’s pretty much all automatic, but it’s also fairly configuration. See the documentation to see what it can do!

6. Reusable Applications

Django projects are broken up into “applications”, and there are lots of existing reusable applications that you can use for your own projects, such as those for user registration, facebook integration, blogging, and many many more.

Existing applications are great, but the whole project/application distinction also forces you to think about your own project structure and therefore more likely to make reusable components that you can use in more of your own projects, or even share for others to use.

7. Templates

I’ve always been a bit dubious about the merits of PHP template engines such as Smarty. The Django template layer is great though. The inheritance model works well, and the restrictive language really forces you to have a very clean separation of presentation and logic.

8. Forms

I usually find dealing with user input one of the most boring parts of web development. It takes time to get it right, and its repetitive. The Django Form API really simplifies things. You can define your form class, include and validation rules, and simply add a few lines to your template and few lines to your view and you’re done!


So those are my 8 reasons why you should give django a go. If you’re already a django user let me know if you have any points to add!

Parsing CSV data in Python

September 3, 2009

Python provides the csv module for parsing comma separated value files. It allows you to iterate over each line in a csv file and gives you a list of items on that row. For example, given the following csv data:

id, name, date
0, name, 2009-01-01
1, another name, 2009-02-01

You’d end up with something like:

["id", "name", "date"],
["0", "name", "2009-01-01"],
["1", "another name", "2009-02-01"]

In some situations it is nice to have a dictionary of keys and values though, so that instead of a simple list of columns we end up with:

{"id": "0", "name": "name", "date": "2009-01-01"},
{"id": "1", "name": "another name", "date": "2009-02-01"}

This would allow us to refer to fields by name rather than position in the list. Do you really want to remember that date is in position 2? And what happens if the input data changes, and a new column is added between name and date? If we’re referring to columns by position then we’ll have to change our existing code, but by referring to it by name we won’t have to change anything.

It turns out this is pretty easy to achieve, in only a few lines of python:

import csv
data = csv.reader(open('data.csv'))
# Read the column names from the first line of the file
fields = data.next()
for row in data:
        # Zip together the field names and values
	items = zip(fields, row)
	item = {}
        # Add the value to our dictionary
	for (name, value) in items:
		item[name] = value.strip()

The csv module allows you to specify a delimiter, so if your data separated you just need to make a single change:

data = csv.reader(open('data.tsv'), delimiter='\t')

Update

Thanks to several people for mentioning csv.DictReader, which does exactly what I’ve mentioned here. Having a look at the code it does something very similar, but also takes into account rows of different length, ignores empty columns, and uses the method Tim mentioned in the comments for creating the dictionary:

    # From csv.py
    def next(self):
        if self.line_num == 0:
            # Used only for its side effect.
            self.fieldnames
        row = self.reader.next()
        self.line_num = self.reader.line_num

        # unlike the basic reader, we prefer not to return blanks,
        # because we will typically wind up with a dict full of None
        # values
        while row == []:
            row = self.reader.next()
        d = dict(zip(self.fieldnames, row))
        lf = len(self.fieldnames)
        lr = len(row)
        if lf < lr:
            d[self.restkey] = row[lf:]
        elif lf > lr:
            for key in self.fieldnames[lr:]:
                d[key] = self.restval
        return d

PyRadio 0.2 Released

June 12, 2009

PyRadio 0.2, the curses based Internet radio player which I develop, is now available!

Changes since the last release include:

  • External radio stations file
  • Page up/down to move up and down 5 stations at a time
  • The selected station remains highlighted when you move about
  • Volume up/down keys
  • Additional radio stations

The latest code available via GitHub, and you can download the 0.2 release from the project page.

Thanks to everyone who left feedback and suggestions about the 0.1 release!

If you find any bugs or would like to request any features then please leave a comment.

Batch Image Processing with Python

November 15, 2008

If you want to make changes to a single image, such as resizing or converting from one file format to another, then you’ll probably load up the image in an editor and manually make the required changes. This approach is great for a single image, but it doesn’t really scale past more than a few images, at which point it becomes time consuming, not to mention boring!

This is where Python and the Python Imaging Library (or PIL) come in, allowing you to write scripts that process images in batch. The PNG2GIF converter I wrote back in August is just one example of batch image processing using Python and PIL. In this post I’m going to explore some other uses, and provide lots of example code.

Batch Processing

No matter what processing we want to do on our images the script outline will be the same: loop over all provided arguments, and perform the processing. The code to do this is shown below:

#!/usr/bin/env python
import sys
import Image

# Loop through all provided arguments
for i in range(1, len(sys.argv)):
	try:
		# Attempt to open an image file
		filepath = sys.argv[i]
		image = Image.open(filepath)
	except IOError, e:
		# Report error, and then skip to the next argument
		print "Problem opening", filepath, ":", e
		continue

	# Perform operations on the image here

This will allow our script to be called in all of the following ways:

batch_process.py image.gif
batch_process.py image1.png image2.gif image3.jpg
batch_process.py *.png
batch_process.py image1.gif, *.png

Processing

With the help of PIL the image processing is really simple. Below is a collection of just some of the operations we could perform. For more details see the PIL documentation.

# Resize an image
image = image.resize((width, height), Image.ANTIALIAS) 

# Convert to greyscale
image = image.convert('L')

# Blur
image = image.filter(ImageFilter.BLUR)

# Sharpen
image = image.filter(ImageFilter.SHARPEN)

Saving

Once we’ve processed the image we need to save the changes. In some instances we might just want to save over the original filename. If that’s the case we can just call the save method of image with its original filename. If we want to save the file under a different name, or as a different filetype we need to do a little more work:

	# Split our original filename into name and extension
	(name, extension) = os.path.splitext(filepath)

	# Save with "_changed" added to the filename
	image.save(name + '_changed' + extension)

	# Save the image as a JPG
	image.save(name + '.jpg')

Notice in the last example how PIL takes care of the conversion to JPG for us. All we do is provide the file extension and PIL does the rest for us.

A Complete Example

Each of the steps above can easily be put together to create a batch image processing script. Below is a complete script which creates thumbnails of all provided images, and saves them as PNG images, not matter what their original format:

#!/usr/bin/env python
# Batch thumbnail generation script using PIL

import sys
import os.path
import Image

thumbnail_size = (28, 28)

# Loop through all provided arguments
for i in range(1, len(sys.argv)):
	try:
		# Attempt to open an image file
		filepath = sys.argv[i]
		image = Image.open(filepath)
	except IOError, e:
		# Report error, and then skip to the next argument
		print "Problem opening", filepath, ":", e
		continue

	# Resize the image
	image = image.resize(thumbnail_size, Image.ANTIALIAS)

	# Split our original filename into name and extension
	(name, extension) = os.path.splitext(filepath)

	# Save the thumbnail as "(original_name)_thumb.png"
	image.save(name + '_thumb.png')

PyRadio 0.1 Released

October 23, 2008

PyRadio 0.1 is now available! PyRadio is a curses based Internet radio player that makes it really simple to play music via the console. It’s written in Python, and uses mplayer for the media playback. The full source code is available via GitHub.

I use Amarok for managing my media collection, and it comes with excellent support for Internet radio. However, Amarok can be fairly resource intensive. That’s why I developed this extremely lightweight console based radio player to make it easy to listen to music without slowing my system down.

For the next release I’m planning to support easy addition and removal of radio stations. Currently you have to edit the actual code if you want to do that. If anyone finds this app useful and would like to request a feature then feel free to leave a comment, either here or on the PyRadio project page.

Older Posts »