Archive for October, 2008
The pyplog code has been moved from Google Code to github.
I plan on starting an i18n branch soon to mark strings for translation.
- I’m a Linux and free software enthusiast. I’m a photographer. Therefore, I tried to get an efficient and professional workflow going under Linux from importing images from my camera, reviewing, organizing and retouching them to publishing. As of now, I don’t think this is possible under Linux. The best I could get was digiKam. It’s a fairly nice piece of software, but doesn’t cover the needs of a (semi) professional photographer. And then there are the issues with running Photoshop CS3 under Linux (the WINE people are working on it though…).
My current solution relies on dual-booting Windows for Bridge and Photoshop (I don’t use Lightroom). Here’s a description of my current setup:- aileen – Headless server
- gentop – Laptop
- dual-booting Gentoo Linux and Windows XP
- running Adobe Bridge and Photoshop CS3
The two external drives are encrypted using TrueCrypt and mounted at aileen:/mnt/backup/{master,slave}. Whenever I’m done with processing a shooting, I sync the disks via rsync to get a redundant backup. I didn’t use any kind of real software RAID.
aileen also runs samba, so I can easily access the master disk from gentop‘s Windows installation.
So, when I get home with my camera, I boot up Windows on gentop, fire up Bridge and have it import the images (converting them to the DNG format) and save them to Z:\photos\archive\YYYYMMDD\ (Z: is the network drive connected to samba on aileen). Next I set Bridge to Vertical Filmstrip mode and apply my labels and ratings in a “binary rating system” as described by Katrin Eismann in one of the video tutorials that come with Photoshop CS3.
When I’m done, I look at the highest rated images first and start the retouching. I have to admit that most of the times I just skip Camera Raw and take the image straight to Photoshop, because I don’t like how the development settings are handled in Bridge/Camera Raw (no easy way of saving multiple sets of settings or to see a complete before and after).
After doing my Photoshop magic, I save the PSD file as YYYYMMDD_title.psd to- released\ – if it’s some artwork I’m going to post here at my web site
- client\doe_john\ – if it’s work for some client
- private\ – if it’s a private piece that is not going to be published anywhere (yet)
Now I can finally reboot to Linux again (my Windows environment has nothing but PS and Bridge – no IM or eMail – to keep me focussed). To upload the finished work I mount the external drives on gentop using sshfs.
Done! Thanks for reading, I hope this can help you to further develop your personal workflow to make it more efficient and fun. =) - aileen – Headless server
- If you’re using generic views in Django, you probably do something like this in your URLconf:
pages = Page.objects.all() [...] url(r"^pages/(?P<slug>.*)$", object_detail, { "queryset" : pages }),Now, say you want to show the title of these pages in a menu on each page. You add a new context_processor:from myapp.pages.models import Page pages = Page.objects.all() def add_pages(): return { "pages" : pages }When you add a page now, you’ll notice that it won’t appear in your menu because the queryset has been evaluated the first time it has been accessed, and will remain the same as long as the python interpreter isn’t restarted. However, generic views appear to do the same thing and still show the most current content. They accomplish this by doingqueryset = queryset._clone()
on each call. A cloned queryset will always be non-evaluated at first, which means that generic views will hit the database each time they’re called. You could of course do that as well, but you feel bad about grabbing those pages out of the database at every single request. My solution for this in pyplog was the following:from django.db.models.signals import post_delete, post_save class CachedQuerySetManager: """ Manages a list of querysets that are automatically updated whenever an object is added to or deleted from one of them. """ def __init__(self): self.querysets = {} def __getitem__(self, key): return self.querysets[key]["queryset"] def add(self, model, manager = "_default_manager"): self.querysets[model] = { "queryset" : getattr(model, manager).all(), "manager" : manager, } post_delete.connect(self.update, sender = model) post_save.connect(self.update, sender = model) def remove(self, model): post_delete.disconnect(self.update, sender = model) post_save.disconnect(self.update, sender = model) self.querysets.__delitem__(model) def update(self, sender, **kwargs): self.querysets[sender]["queryset"] = \ getattr(sender, self.querysets[sender]["manager"]).all() cached_querysets = CachedQuerySetManager()The above example would look like this:from myapp.pages.models import Page from myapp.util.query import cached_querysets cached_querysets.add(Page) def add_pages(): return { "pages" : cached_querysets[Page] }Now the queryset is reset everytime a page is added or deleted. Note that you should of course only do this with QuerySets that you can afford to completely keep in memory (read: just a couple of objects). The QuerySet passed to a generic view never gets evaluated itself, so that it’s very cheap to have it around. The above code however keeps the evaluated QuerySet and will increase memory usage in favor of database load.
You probably won’t need this if you’re using traditional caching (memcached), but for the folks that choose to go without it, this little helper might come in handy.
Note that the CachedQuerySetManager class above is part of pyplog and therefore published under the GPL license. See pyplog’s LICENSE file for more information.


