Brack.io Thoughts, stories and ideas

Image Conversion in Python

Yesterday I had to convert a lot of pictures to different formats. I quickly came up with a Python Script that searches a specified path recursively for images and converts them to one or more output format. It’s nothing fancy, and it was late at night so don’t blame me for bad code. I just thought I’d share it here because it might be useful for someone. In order to run this script you need to have PIL installed.

import os
import sys
import Image
class ImageConverter(object):  	
	def __init__(self, typesin, typesout):
		"""constructor"""
		self.typesin = typesin
		self.typesout = typesout

	def SearchFiles(self, path):
		if path[-1] != '/':
			path += '/'

		print "searching files in " + path
		for root, dirs, files in os.walk(path):
			for fname in files:
				fullpath = os.path.join(root, fname)
				if os.path.splitext(fname)[1] in self.typesin:
					self.ConvertImage(fullpath)

	def ConvertImage(self, filepath):
		for t in self.typesout:
			outfile = os.path.splitext(filepath)[0] + t.lower()
			print "converting image %s to %s" % (filepath, outfile)

			try:
				im = Image.open(filepath)
				im.save(outfile)
			except IOError as detail:
				print "failed to convert file %s" % (filepath)

			except:
				print "Unexpected error:", sys.exc_info()[0]
				raise
if __name__ == '__main__':
	if len(sys.argv) == 1 or len(sys.argv) > 2:
		print 'Usgae: python ' + str(sys.argv[0]) + ' /path/to/search/'
	else:
		converter = ImageConverter(['.gif',], ['.tiff',])
		converter.SearchFiles(sys.argv[1])

I think the script is pretty self-explanatory. Simply pass the path to search for images as a command line argument. When instantiating the class, you can pass the input and output formats as a list.

I think that’s it for today.

Extend Django's manage.py command

In Django 1.0 it’s very easy to extend the default functionality of the manage.py command. I use it to delete the comments that have been marked as spam. The cool thing is that you can access the data model using the ORM. So, let’s see how this whole thing works.

First off, we need to create a management folder within our application. In there, we need to create a folder called ‘commands’. This is the place where we can put our Python scripts. Don’t forget to create the __init__.py files in both folders. The directory structure should look something like this

app/
    __init__.py
    models.py
    management/
        __init__.py
        commands/
            __init__.py
            greatcmd.py
    views.py

As you can see above, I have already created a file called greatcmd.py within the commands directory. The name of the file will also be the name of our command. In this example, we would execute the command like this

./manage.py greatcmd

Now let’s take a look inside the greatcmd.py file

from django.core.management.base import BaseCommand
class Command(BaseCommand):
	help = "This doesn't do anything yet"
	def handle(self, *args, **options):
		print 'greatcmd was called'
		# other fancy code here

That’s basically it. You can add pretty much anything in the handle method. It’s also possible to import your models etc. Pretty convenient and straightforward. Please note that you have to be in your application’s directory when executing the manage.py command. Otherwise you won’t be able to run the custom command.

If you wanna know more about it, take a look at the official Django Documentation. If you’re interested in how I fight spam in my Django Apps, feel free to read my other post Preventing Spam In Dango.

Django Admin tweaks

In an earlier post I wrote about adding a WYSIWYG editor to Django’s Admin interface. As a fallow up, I’d like to share some thoughts about an interesting project I came across recently. It’s called django-grappelli and is hosted on Google Code. It basically changes the whole look of the Django-Admin interface. Some people might not like that as they love the original look. I have to say, I like the original look too but I think django-grappelli just improves the interface dramatically! The look & feel is totally different. When I first used it, I really thought, whow, this is big. They even added a nice looking TinyMCE theme.

So I have to say, everything looks complete and consistent. Anyway, enaugh teasing. Check out the screenshot below and make sure to visit the project site here.

Grappelli Admin Interface

Create a simple site search with Django

It’s been a while since I wrote my last post. I’ve been rather busy the last couple of months. Today I finally found some time to write down some stuff. Initially I wanted to write about Django’s Q object and later about how to create a simple site-search with Django. I decided to combine these two topcis and just write one post.Let me first say, I don’t know if that’s a good way to build a site search with Django. It works great for me as I don’t have a lot of content that has to be searched. If you are looking for a more flexible and more reliable Django-Search, you should check out Haystack.

Having said this, let’s get started.

First we need to create a Form in our ‘views.py’ file. To do so, add the following code to your views.py file

import django.forms as forms

class SearchForm(forms.Form):
    query = forms.CharField(label="")

Now we can pass this form to our template

f = SearchForm()
myform = {'form':f}

Serve Django on Gentoo with lighttpd

In this post you’ll find a step by step guide on how you can serve your Django site on Gentoo, using lighthttpd and FastCGI. Even though this guide is written specifically for Gentoo, it might also help you if you use another Linux distribution.

Let’s start by installing the required packages. As root, run the following command (flup is required for Django’s init.d script)

emerge flup lighttpd

Next, go and grab yourself a copy of Django’s InitdScript for Gentoo and give it an appropriate name. Mine is called django-fastcgi. Just to mention it, a version for other Linux distributions is also available here. The script is pretty self-explaining. You only have to change the DJANGO_SITES and SITES_PATH variables. The DJANGO_SITES variable is the name of your Django project, and the SITES_PATH variable is the path to your project (without a trailing slash I think). Let’s assume the absolute path to your project is /var/www/myproject/. The configuration for this setup would look like this

DJANGO_SITES="myproject"
SITES_PATH=/var/www
RUNFILES_PATH=/var/django/run
HOST=127.0.0.1
PORT_START=3000

Now you can copy the script to the init.d directory by running

cp scriptname /etc/init.d/

Make sure the script is executable

chmod +x /etc/init.d/scriptname

Try to start the fast-cgi process like this

/etc/init.d/scriptname start

If you don’t see any errors showing up, you can add the script to the default runlevel to start the script automatically if you have to reboot your server or so. In order to do so, simply run

rc-update add scriptname default

Alright, still with me? Cause we’re not done yet. We can now configure our lighttpd server. With your editor of choice, open up lighty’s config file. You can find it in /etc/lighttpd/lighttpd.conf. Make sure you have the following modules enabled

server.modules = (
	"mod_rewrite",
	"mod_redirect",
	"mod_alias",
	"mod_access",
	"mod_fastcgi",
	"mod_accesslog"
)

Now let’s configure lighty to work with our fast-cgi process. Somewhere at the bottom of the configuration file, add the following part

$HTTP["host"] =~ "(^|\.)yourdomain\.com$" {
    server.document-root = "path/to/your/django/project" # same path as the SITES_PATH in the fastcgi script
    server.errorlog = "/path/to/your/logdir/yourdomain-error.log"
    accesslog.filename = "/path/to/your/logdir/yourdomain-access.log"
    fastcgi.server = (
        "/youdomain.fcgi" => (
            "main" => (
                "host" => "127.0.0.1",
                    "port" => 3000,
            )
        ),
    )
    alias.url = (
        "/media" => "/usr/lib64/python2.5/site-packages/django/contrib/admin/media/",
        "/favicon.ico" => "/path/to/favicon/favicon.ico",
    )
    url.rewrite-once = (
        "^(/media.*)$" => "$1",
        "^/favicon.ico" => "/favicon.ico",
        "^(/.*)$" => "/yourdomain.fcgi$1",
    )
}

Some quick notes about this. The regex pattern at the top makes sure you can use both www.yourdomain.com and yourdomain.com to visit the site. The media alias url is used for the Django Admin site and it’s media content. So change this path to wherever you have installed the Django source-code. The favicon part is optional. You only have to add that if you actually have a favicon and want to display it. As you can see, there’s also another fast-cgi script mentioned in the configuration. We are going to create this file now. Open an editor and put the following line in it

#!/bin/sh
export DJANGOSETTINGSMODULE=yourproject.settings.main

Place this script in your Django project folder. Also make sure it is executable

chmod +x /path/to/your/docroot/yourdomain.fcgi

Now try to start lighttpd

/etc/init.d/lighttpd start

If this works, you can also add lighttpd to the default runlevel

rc-update add lighttpd default

Ok, now you should be able to visit yourdomain.com and see your Django application. When I first tried this, I ran into a small problem. Sometimes, the url looked weird because it displayed the name of the fast-cgi script in it. I was able to solve this issue by adding the following line to my settings.py file

FORCE_SCRIPT_NAME = ''

I hope I didn’t miss anything, since it’s already been a while when I set up this environment.

One last note, you could also run the Django fast-cgi process using Unix sockets rather than using a TCP connection. I didn’t try it myself but it looks pretty easy. You can find more information about that here.

I hope this post helps some people to get things running correctly.