Greg Aker

Simple Desktops for the Mac!

Filed in: Announcements, Blobbing, Django

September 7, 2011

I'm completely stoked that the Simple Desktops app for the Mac is now available in the App Store. I took over the reigns of site development from Kenny Meyers in early 2011. Since then, Tom Watson and I have been trucking along making a lot of small tweaks leading up to this app.

Simple Desktops

I introduced Tom to Justin Voss who by day is a Java Programmer at a very large Enterprise here in Columbia, MO, but by night is an amazing Cocoa and Django developer. The collaboration on this was a ball. Tom had the vision, Justin made it happen, and I gave Justin an API to interact with existing data.

All things considered, the API was stupid simple to implement, thanks to Django-Piston. Jesper at BitBucket gave Django developers are real gem by releasing this code. When it was all said and done, it was accomplished in under 50 lines of Python.

For anyone interesting in Piston, here's a bit of how I accomplished things. We have a RandomDesktopHandler which is pretty simple:

class RandomDesktopHandler(DesktopsHandler):
    def read(self, request):
        return Desktop.live.select_related().order_by("?")[0]

What initially tripped me up was wanting to display fields in the API that weren't in the Desktop object. In order to facilitate previous/next desktop functionality in the Mac App, this is something we needed.

Basically, this is how we accomplished it:

from piston.handler import BaseHandler
from desktops.models import Desktop

class DesktopsHandler(BaseHandler):
    fields = ('pk', 'title', 'next_url', 'previous_url', )
    model = Desktop

    def read(self, request):
        # read method

    @classmethod
    def next_url(cls, desktop):
        url = desktop.get_next()  # grab the next live desktop
        if not url:
            return None
        return url.get_api_absolute_url()

    # previous_url here...

get_api_absolute_url() is a @models.permalink method on the desktop model. By making it a class method in the api handler, we are able to access it as a field in the API response.

The last bit that got us was caching. Piston/Django are sending 600 second cache headers, which are no good if we want truly random results. So we threw together a quick cache killer to use in the api urls file.

def cache_killer(view):
    def inner_view(request, *args, **kwargs):
        response = view(request, *args, **kwargs)
        response['Expires'] = 'Mon, 26 Jul 1997 05:00:00 GMT'
        response['Cache-Control'] = 'max-age=0, private, no-cache, no-store, must-revalidate, proxy-revalidate, no-transform'
        response['Pragma'] = 'no-cache'
        return response
    return inner_view

And with that, we get random results on every hit!

Being a paranoid sysadmin, this does makes me nervous. Will Postgres get beat to death? We have more than web traffic to worry about now. So I decided to throw Varnish in front of most of the pages for now. This helps to mitigate load on the database server, so everyone can live in harmony.

I'd be remiss if I didn't send huge props to on of my most favorite icon designers Louis Harboe. He totally killed the design of the apps icon. I'd also be way more of a wreck if the Desktops weren't on the EngineHosting CDN.

I hope your enjoy the initial offering. Go get it, rate it and let us know what you think. We have even more up our sleeve, so stay tuned.

Shameless plug

Want to learn some more Python? Check out my screencasts at Mijingo.