Django simple admin ImageField thumbnail

June 20th, 2009

The Django admin site is one of the best features of Django. It really lets you just get on with building your app, without having to worry too much about how you’ll administer your site.

The defaults are generally pretty good, but it’s often the case that you’ll want to tweak and change it (particularly when you have clients involved). Luckily it’s pretty easy to customize.

One common change that many people will want to do is to display a thumbnail of an uploaded image in the admin. The default image field (when an image has been uploaded) in the admin looks like:

image_field1

and we want to change it to look like this:

image_field2

In my case I had images that I knew would be fairly small so I didn’t need to use any auto-resizing or anything like that. I found this snippet for doing the same task, but decided to simplify it a fair bit and ended up with:


from django.contrib.admin.widgets import AdminFileWidget
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe

class AdminImageWidget(AdminFileWidget):
    def render(self, name, value, attrs=None):
        output = []
        if value and getattr(value, "url", None):
            image_url = value.url
            file_name=str(value)
            output.append(u' <a href="%s" target="_blank"><img src="%s" alt="%s" /></a> %s ' % \
                (image_url, image_url, file_name, _('Change:')))
        output.append(super(AdminFileWidget, self).render(name, value, attrs))
        return mark_safe(u''.join(output))

Then to use it I simply override formfield_for_dbfield to return a field that uses that widget for the field I’m interested in:


class MyAdmin(admin.ModelAdmin):
    def formfield_for_dbfield(self, db_field, **kwargs):
        if db_field.name == 'profile_image':
            kwargs['widget'] = AdminImageWidget
            return db_field.formfield(**kwargs)
        return super(MyAdmin,self).formfield_for_dbfield(db_field, **kwargs)

It’s a fairly straightforward alteration to how the ImageField widget renders in the admin, but it is often a big help to be able to actually see the image in question.

Introducing NoteComb

May 18th, 2009

I’ve been writing an application for my other half in recent months to help her organise observations of the children in her class. I’ve actually written two versions of the app. The first was dubbed “Observertron” and in retrospect was overly complex. After a bit of thought I was able to vastly simplify the app, whilst also making it more useful for other purposes beyond making observations.

The app is called NoteComb and is written in Python using wxPython. It’s essentially a specialised text-editor. The core feature is a grep-like search functionality coupled with the ability to edit text in-place during a search. Lines that don’t contain the search terms get hidden, leaving you free to edit the remaining lines as you want:



I’ve decided to take the time and try to package it up “properly”. So NoteComb is available as Mac and Windows apps, complete with icons etc. In fact to “regular” users it should appear that NoteComb is an app like any other – the fact it’s written using Python is largely incidental.

This packaging works pretty well overall and is pretty seamless once the app is downloaded, but it does tend to make for rather large apps. The Windows version when packaged as an installer runs in at about 4Mb, which isn’t too crazy, but the OS X app packed into a compressed DMG file weighs in at 15Mb! At the end of the day the app does include Python + wxPython + various libraries, so it’s not a surprise really, but I guess I was kind of hoping that I might develop in Python and get everything for free…

This is an early version of NoteComb (version 0.2.1), but it’s core functionality is there. Most of the extra work I’ve done has been on adding those little extra bits that aren’t core to the app, but are generally just expected (e.g. remembering previous window positions, copy/paste, undo/redo etc).

So feel free to download NoteComb and give it a go.

Easily setting frame icon from exe file in wxPython

May 1st, 2009

I’ve updated the relevant wxPython wiki page with this info, but thought i’d record it here for posterity too.

I’m currently playing around with writing a wxPython app. It’s at the point where I’m starting to package it into executables to be run without needing Python installed.

Py2exe is the tool I’m using for creating a windows app (and py2app for the mac). It’s possible to specify an icon for the executable you create with py2exe. However it’d be nice if this same icon would be used as the icon for frames created by that app. One could include an extra icon as a resource and load that up, but this seems counter to the whole DRY principle. Instead it’d be better to load the same icon from the executable we have created already.

Consulting the wxPython wiki showed that some enterprising souls had already had a go at doing this, but the solutions there relied on the win32api modules amongst others. My Windows machine didn’t have this module installed (as it was running Python 2.5) and looking at the 2nd solution proposed I saw a way to remove this dependency (and thus decrease the size of the final exe as it would not need to include the extra dll’s etc).

So here’s the sample code, from the wiki, I posted:


import wx, sys

class MyFrame(wx.Frame):
    def __init__(self, parent=None):
        wx.Frame.__init__(self, parent, wx.ID_ANY)
            # set window icon
            if sys.platform == 'win32':
                # only do this on windows, so we don't
                # cause an error dialog on other platforms
                exeName = sys.executable
                icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
                self.SetIcon(icon)

if __name__ == '__main__':
    app = wx.App(redirect=False)
    frame = MyFrame()
    frame.Show(True)
    app.MainLoop()

Basically it uses sys.executable to find the exe we are running in and then gets wxPython to load the first icon it finds from it (which should be the icon of the executable itself). So when you run this directly from python (not packaged), you end up with the icon from the python executable, but when you run the packaged version you get the icon from the exe instead.

It includes the platform check, as otherwise the app throws up an error dialog on the mac and obviously I want this to work on both platforms (and Linux too in the future).

Playing with paint: girl with a 286

April 17th, 2009

Following (chronologically in chip fabrication order) on from Girl and an Altair 8800 and Girl and an Apple II is “Girl with a 286″:

Girl with a 286 the final version

The 286 in question being Intel’s 80286 chip – the motherboard of which can be seen in the background of this painting.

This particular painting is much larger than the previous two. Rather than the A4 size of the previous, it’s 40″ tall. This is because it will be featured in Congregation 2009 along with many other “life-size” portraits.

So if you want to see this painting in the flesh please go visit St Paul’s Church from the 4th-25th of May between 1.30pm and 4pm.

A Huffduffer Widget

March 22nd, 2009

When Jeremy talked about Huffduffer at March’s £5app he revealed that pretty much every page in Huffduffer had a RSS/JSON/XML version. A couple of weeks back, I asked whether Huffduffer supported JSONP. After a quick reply back from Jeremy that it wasn’t, there was another reply within an hour or two saying Jeremy had added JSONP support. At that point I felt my curiosity had got the better of me and I felt duty bound to a least do something with the newly added JSONP support…

So here I present a very simple embed-able Javascript widget for Huffduffer:



Both the page used to generate the widget HTML and the widget code itself are 100% client-side. There’s no server-side code involved at all. For the widget itself this seemed pretty key. Such widgets may be embedded in pages that get a lot of hits, so doing anything beyond serving up a static file seemed best to avoid.

I’d not really written a widget like this before, but planned to create something similar for chrss at some point, so it seemed like a good thing to have a go at. Most of the techniques are based on code from Dr Nic’s DIY widgets – How to embed your site on another site article. However I tried to add a few more features/constraints into the mix:

  • Allow more than one widget with different data on the same page
  • Don’t pollute the global namespace
  • Don’t require special html embedded with the widget (just a single script tag)
    • The first point involved allowing a static javascript file to server different data. The easy way would be to have some server side code serve up some slightly different Javascript depending on the parameters given, but I decided there’s no reason why the Javascript can’t do that itself.

      When the widget script runs it looks at the last known script element – which should be the element used to load the script itself to parse the parameters. In this case I just want a single parameter. So if the script tag used to embed the widget looks like this:

      <script src="http://psychicorigami.com/huffduffer/build/huffduffer.js?lilspikey" type="text/javascript"></script>
      

      I can extract everything after the ? thus:

          function findURL() {
              // assume that last script in page is this script
              var scripts = document.getElementsByTagName('script');
              var script = scripts[scripts.length-1];
              var scriptURL = script.getAttribute('src');
              var m = scriptURL.match('^.*\\?(.*)');
              if ( m ) {
                  return m[1];
              }
              return ''
          }
      

      So that solves the first problem.

      The next problem is not polluting the global namespace. First I make sure that everything is wrapped inside an anonymous function that is called immediately. This reduces the scope of the functions declared in there. However we do need at least one global function to act as a callback for the JSONP data. In addition this function must be unique to each widget embedded in the page, so that the correct data gets given to the correct widget.

      So first I generate a relatively unique id:

          function uuid() {
              var id = "_"+(new Date()).getTime();
              for ( var i = 0; i < 8; i++ ) {
                  id += "0123456789".charAt(Math.floor(Math.random()*10));
              }
              return id;
          }
          var id = uuid();
          var div_id = 'huffduffer'+id;
      

      Then we use that id as a name for the function and create a callback that embeds the id of the div the widget will appear in via a closure:

          function createCallback(div_id) {
              // return a function with the div_id in a closure
              return function(data) {
                  // real callback code here
              }
          }
      
          // create a function with a generated name, to ensure
          // we get the right div
          window[id] = createCallback(div_id);
          document.write("<div id='"+div_id+"'></div>");
      

      This means that we can have multiple widgets on the page all showing different data and the global namespace pollution is limited to one randomly named function per widget.

      In addition by creating this unique id we can tie the callback function to the relevant div in the page without needing any more magic. Which means we've also dealt with the third problem.

      The "real" widget has been minimized using YUICompressor, but you can see the regular version of the code here:

      I've tested everything in most of the major browsers, but can't guaranteed it'll work perfectly everywhere.

5K Morse Code App Using Capslock LED

March 1st, 2009

This is probably my first attempt at “literary programming”, though using that phrase may be taking liberties a little. In this case by “literary programming” I mean – programming inspired by literature. The literature in question is Cryptonomicon by Neal Stephenson. Cryptonomicon already features a Perl script in it’s pages, but that’s not what I’m talking about here. Instead there’s a chapter later in the book when Randy Waterhouse has been incarcerated. However he’s been given the use of his laptop so that – his captors hope – he will decrypt a key piece of data whilst they are monitoring his screen via Van Eck Phreaking. Randy cottons onto this, so he creates an app that will convert text to morse code and have that morse code emitted via the LEDs on his laptop’s keyboard.

I suddenly decided to have a go at creating such a morse code script for my Macbook and here’s the result in action:


You can test the script out by running this at the command line (from the directory with the script in):

echo 'sos' | python morse.py -led

It depends on libraries that are only found in OS X 10.5 Leopard for controlling the capslock LED.

With a bit of compression it all fits well under 5K of code, so makes a worthy example of a 5K app. The morse part of the app is very simple – apart from the lookup table, it could probably fit into 2-3 lines of code! The bulk of the code is simply concerned with driving the capslock key’s LED via the HID. For this I cribbed heavily from some of Apple’s sample code and converted it to run in Python using ctypes.

The only problem I found was that for some reason they internal keyboard on my Macbook stops responding to the request to change the LED state after several seconds. However using this script with an external USB keyboard worked fine. I guess the internal keyboard has some sort of abuse-prevention built-in.

Python Meet and 5K app reminder

February 7th, 2009

The next Brighton and Hove Python User Meet will be the 18th of February 2009 at the Hampton Arms Farm Tavern. As per usual we’ll be sharing the venue with the Farm. Now that there’s a google group setup for these meets they might happen a bit more often, as Ian and I will no longer be the limiting factor!

A quick reminder too that the next £5app meet is now only a few weeks away on the 3rd of March. Jeremy Keith will be talking about Huffduffer (which I’ve been using a lot for getting great podcasts for the walk home after work) and we’ll be running the 5K app competition. The deadline for the 5K app is the Friday before the event (27th Feb), so there’s just under three weeks left to get something written.

If anyone wants to chat about the 5K app they’re welcome to pop along to the Python User Meet too. I’m more than happy to spend some time helping people get their code under the 5K budget.

Announcing the Brighton and Hove Python User Group Google Group

January 29th, 2009

After managing to organise two previous Python meetups and failing to organise many more it seemed like a good time to set-up mailing list of some sort so that things can self-organise a bit more. So please sign-up for the Brighton and Hove Python User Group Google Group (BHPUGGG) and hopefully there will be a few more meetups more often.

For any Pythonistas out there you might want to have a look at the 5K app competition. The idea is to write apps that are less than 5120 bytes in size. It’d be great to see some small Python apps entered and with Python (and a bit of self-extracting script fun) they should pack quite a punch!

Converting a pair of trousers into a laptop sleeve

January 18th, 2009

I ordered one of the new metal Macbooks on the night they came out. So far it’s been a great machine, but there has been one minor problem – it’s a different size to my old 12″ Powerbook. So obviously my old crumpler laptop case was going to be no use.

After purchasing some green cotton thread, grabbing an old pair of trousers and a couple of hours sewing (by hand) I ended up with a perfectly workable laptop sleeve for my Macbook:

A 5K Java Guitar Tuner

January 17th, 2009

So after writing a 5K Twitter Client, a 5K TODO app and a 5K Fullscreen Text Editor I thought that’d be enough example apps to get things started. However while adding a list of app ideas to the 5K App page I suddenly decide that one of the ideas really appealed. The idea was to write a guitar tuner, that would listen on the computers mic and show the user what pitch it thought the note played was. I’m not much of a guitar player, but when I do play it’s always nice to have a guitar that’s in tune. As I’m unable to tune a guitar by ear I rely on guitar tuners and I always seem to be out of the 9V batteries my electronic tuner needs. Given my laptop is usually nearby, being able to use it as a guitar tuner would be most useful.

Check out the video below or download 5KTuner for yourself (requires Java):



The app is more or less non-interactive. It simply starts up tries to work out what note is being played. It shows a simple slider that moves according to what note is being played and indicates how close to that note you are. In addition the raw frequency (in hz) is shown, as well a chart that shows the autocorrelation function of the input sound. A red line is drawn on this chart when a “valid” note is heard and indicates the wavelength of the overall frequency.

The vital statistics are:

  • Final (obfuscated) app size: 3538 bytes
  • Final (un-obfuscated) app size: 4649 bytes
  • Final Source-code size: 8532 bytes
  • Lines of code: 245

This was my first foray into audio programming and I’m grateful that in the end it wasn’t too tricky. Initially I’d been looking into using the Fast Fourier Transform to work out the frequencies, but the autocorrelation function was much easier. It’s essentially just two for loops and a bit of maths. You listen for a certain amount of audio and then compare the first half of the sample with itself, but shifted. By working out the amount of shift where the difference is smallest you can find the overall frequency of the sample.

It could probably be made more robust, but if you want to see how it works (or improve it) you can download the source code.