mogileFS for Django
Posted September 4th, 2008 by andrewIn preparation for DjangoCon, I thought I’d release a little bit of quickly-written-code (read: easily improvable!) that we use to serve our avatars on Fluther.
Here’s the basic rundown:
- Get mogilefs on your box
- Patch django to support different FileBackends
- Get data into mogile
- Get data out of mogile
Getting mogile
We use Ubuntu on our production boxes, and it just so happens that I’m the debian maintainer for mogile. So. Get the packages from https://edge.launchpad.net/~awmcclain/+archive (add the entries for your distro onto your source.list, run apt-get update then apt-get install mogilefsd mogstored). Setting up mogile is a little beyond this document, but check out the google group if you have any troubles.
Patch Django (optional)
I see that Marty’s work has been incoporated into Django’s 1.0 beta (congrats, Marty!), but if you’re running an older version (like we are), you’ll need to patch your codebase to support file storage backends. See the patch at http://code.djangoproject.com/ticket/5361
Install the mogile backend
Download the zip of the files and throw filestorage.py and mogilefs.py somewhere on your pythonpath. The models.py file contains some example code, as well as an urls entry.
Set up the mogile backend
The mogile filestorage backend is fairly simple: it uses URLs (or, rather, parts of URLs) as keys into the mogile database. When the user requests a file stored by mogile (say, an avatar), the URL gets passed to a view which, using a client to the mogile tracker, retrieves the “correct” path (the path that points to the actual file data). The view will then either return the path(s) to perlbal to reproxy, or, if you’re not using perlbal to reproxy (which you should), it serves the data of the file directly from django.
In order for the backend to work, we need to add a few settings variables:
- MOGILEFS_DOMAIN: The mogile domain that files should read from/written to, e.g “production”
- MOGILEFS_TRACKERS: A list of trackers to connect to, e.g. [”foo.sample.com:7001″,”bar.sample.com:7001″]
- MOGILEFS_MEDIA_URL (optional): The prefix for URLs that point to mogile files. This is used in a similar way to MEDIA_URL, e.g. “/mogilefs/”
- SERVE_WITH_PERLBAL: Boolean that, when True, will pass the paths back in the response in the ‘X-REPROXY-URL’ header. If False, django will serve all mogile media files itself (bad idea for production, but useful if you’re testing on a setup that doesn’t have perlbal running)
- DEFAULT_FILE_STORAGE: This is the class that’s used for the backend. You’ll want to set this to “project.app.filestorage.MogileFSStorage” (or wherever you’ve installed the backend)
Gettings files into mogile
The great thing about file backends is that we just need to specify the backend in the model file and everything is taken care for us — all the default save() methods work correctly.
For Fluther, we have two main media types we use mogile for: avatars and thumbnails. Mogile defines “classes” that dictate how each type of file is replicated — so you can make sure you have 3 copies of the original avatar but only 1 of the thumbnail.
In order for classes to behave nicely with the backend framework, we’ve had to do a little tomfoolery. (This is something that may change in future versions of the filestorage framework).
Here’s what the models.py file looks like for the avatars:
from django.core.filestorage import storage
# TODO: Find a better way to deal with classes. Maybe a generator?
class AvatarStorage(storage.__class__):
mogile_class = ‘avatar’
class ThumbnailStorage(storage.__class__):
mogile_class = ‘thumb’
class Avatar(models.Model):
user = models.ForeignKey(User, null=True, blank=True)
image = models.ImageField(storage=AvatarStorage())
thumb = models.ImageField(storage=ThumbnailStorage())
Each of the custom storage classes defines a “class” attribute which gets passed to the mogile backend behind the scenes. If you don’t want to worry about mogile classes, don’t need to define a custom storage engine or specify it in the field — the default should work just fine.
Serving files from mogile
Now, all we need to do is plug in the view that serves up mogile data. Here’s what we use:
urlpatterns += patterns(”,
(r’^%s(?P<key>.*)’ % settings.MOGILEFS_MEDIA_URL[1:], ‘panda.main.filestorage.serve_mogilefs_file’)
)
Any url beginning with the value of MOGILEFS_MEDIA_URL will get passed to our view. Since MOGILEFS_MEDIA_URL requires a leading slash (like MEDIA_URL), we strip that off and pass the rest of the url over to the view.
That’s it! Happy mogiling!
Explore posts in the same categories: Fluther, News, Technical
September 5th, 2008 at 1:31 am
I’m going to say something like “Interesting” to make it sound like I know what is going on here…
September 5th, 2008 at 4:31 am
Ha. I will do the same as mukaki. “Fascinating…”
September 5th, 2008 at 9:12 am
September 5th, 2008 at 9:12 am
(tries to shake his eyes out from their cross-eyed state)
September 5th, 2008 at 12:35 pm
Very Intruiging!
What’s it mean?
September 5th, 2008 at 3:34 pm
I already knew all that.
September 5th, 2008 at 3:47 pm
Yeah, Gail told me all that like a week ago.
September 5th, 2008 at 3:49 pm
But it does have a lovely bouquet, with a slght afterbite of halapeño and catnip.
September 6th, 2008 at 8:34 am
That’s a pretty sweet setup. I’ll add the repo’s to my Ubuntu server at home later and tinker with it. I never would have thought that fluther ran off python, though. I think that is really impressive and shows that python is hardly the dead language PHPers, .NETers and RoR’s would lead everyone to believe. And Django is awesome. I just read some write-ups at BandN about where it’s going and what’s next. Hurrah!
September 7th, 2008 at 12:32 am
oh, duh.
September 8th, 2008 at 2:19 am
May I add your mogileFS storage to the django-storages project (and your blog post as documentation)?
http://code.larlet.fr/django-storages/
http://code.larlet.fr/doc/django-s3-storage.html
Anyway, thanks for your code
September 8th, 2008 at 7:34 pm
I would make another clever retort, but I am too busy jailbreaking my iPhone.
September 12th, 2008 at 7:06 pm
(No. The motto here is “Everything in moderation.”)
September 14th, 2008 at 1:34 pm
@tWrex - I thought it was the other way around… RoRers and Pythoners claiming PHP was dead
September 16th, 2008 at 1:02 pm
@david: Sure thing! Sometime soon I’m going to try and convert this into a pluggable app, but go ahead!
December 11th, 2008 at 4:33 am
Thanks for this post Andew.
What are the scalability ramifications of this approach? It looks like all your media requests are proxied via mod_python - doesn’t this go against Django’s suggested way of separating out (and therefore optimizing) media requests?
February 13th, 2009 at 5:02 pm
In searching for sites related to web hosting and specifically comparison hosting linux plan web, your site came up.
June 25th, 2009 at 3:58 pm
? i didnt get that because i got on here today and im really confusted
June 25th, 2009 at 4:00 pm
interesting
June 25th, 2009 at 4:01 pm
omg i just hear that michale jackson died
June 25th, 2009 at 4:02 pm
no im not lieing about his death and its really its says on the news in the labtop
at my house and its a pretty good one
August 14th, 2009 at 11:18 am
filestorage.py and mogilefs.py of the Mogile backend zip file are identical. I think that mogilefs.py was overwritten.