Sublime Text, iTerm, Cyberduck

I am still working away at the site. Hopefully, my next post will be a cumulative update on some of the interesting facets of Django, GridFS and MongoDB.

In an earlier post, I mentioned the django-easy-maps package, I have moved away from it. It is excellent, but it is limited when you want to specify multiple markers and attach event handlers to the map navigation.

Hopefully more on that later as well.

I thought I would use this entry to discuss the programming environment that I am using for the site.

I use a 2010 Macbook Air. It can be a bit slow at times, but it handles VMware Fusion well which allows me to run multiple OSes at the same time. Useful for quickly deploying a server, provide snapshot capabilities and flip back and forth between environments (using spaces).

I use Cyberduck for connecting to either local or remote servers (specifically Linode) and for text editing. It is an excellent application and I highly recommend donating to the project if you use the application.

For years, Textmate has been my editor of choice on OSX. I use vi while connected to servers (sorry emacs fans). However, I recently decided to move over to Sublime Text and I am hooked. I have made it my default editor for Cyberduck which automatically opens files in new tabs (a particular pet peeve with Textmate unless you launched it via terminal). The autocompletion and function list capabilities are excellent.

As for ssh access to servers, the base Terminal application is adequate but I prefer iTerm. It is useful for reloading gunicorn whenever non-template files are modified in Django.

Finally, the webkit developer tools provided in Chrome are excellent. I have used Firebug in the past in Firefox, but with the recent Firefox release acceleration and the fact that the lead developer on the Firebug plugin is working with Google, Chrome is the (IMO) the best browser for web development.

Add to that a comfy chair, footrest and side table (and associated alcoholic beverage) and you have my preferred development environment!

Django, Nginx and GridFS Con’t

Whew.

Took a little while longer than I anticipated but I have successfully managed to get uploaded files into MongoDB using GridFS and then served through nginx-gridfs in a nifty modal media viewer called Shadowbox.js.

In an earlier post I covered recompiling Nginx in Ubuntu to add the nginx-gridfs module. The steps outlined in that post are necessary before proceeding.

Django Model

As stated earlier, I am using the excellent Django MongoDB Engine which will allow base Django model FileField to upload files directly to GridFS as opposed to the local filesystem. Here is the models.py configuration that worked for me:

from django_mongodb_engine.fields import GridFSField
from django_mongodb_engine.storage import GridFSStorage

gridfs = GridFSStorage()
images = GridFSStorage(location='/gridfs')

Then in your specific model definition, define your FileField (or ImageField) as such:

class Foo(models.Model):
    ...
    file_1 = models.FileField(storage=gridfs, upload_to='gridfs')
    ...

Uploaded files will store the path and filename in the file_1 key/value store. So, bar.jpg would be stored as gridfs/bar.jpg. This is important later on.

Nginx

There are ways of serving files stored in GridFS directly out of Django but it is not recommended. The preferred approach is nginx-gridfs which is fairly easy to configure once you have defined your Django models.

The root_collection parameter is necessary as it assumes that the fs collection is used by default. Django MongoDB Engine appears to use storage.images/storage.files by default so you will need to specify either one in. Second, if you do not specify a field or type value, requests to example.com/gridfs/ will need to use the ObjectID (_id) to retrieve the specific files.

Since the Foo class will store the values using the path and filename, you will not know the ObjectID of the objects through a standard query.

location /gridfs/ {
    gridfs database root_collection=storage.images field=filename type=string;
    mongo 127.0.0.1:27017;
}

Once you restart Nginx, requests to example.com/gridfs/bar.jpg should return the uploaded file.