django-syncr and machine tags

django-syncr is a powerful Django app that supplies everything needed to sync your project with several web APIs. I've used it several times and I've always been amazed by the quality of the code. In this article, I'll show you how easy is to add machine tags support to the Flickr app.

Machine Tags

From flickr:

Machine tags are tags that use a special syntax to define extra information about a tag.

Machine tags have a namespace, a predicate and a value. The namespace defines a class or a facet that a tag belongs to ('geo', 'flickr', etc.) The predicate is name of the property for a namespace ('latitude', 'user', etc.) The value is, well, the value.

Like tags, there are no rules for machine tags beyond the syntax to specify the parts of a machine tag. For example, you could tag a photo with :

  • flickr:user=straup

  • flora:tree=coniferous

  • medium:paint=oil

  • geo:quartier="plateau mont royal"

  • geo:neighbourhood=geo:quartier

Say, for example, that you have a blog and want to use machine tags to associate flickr photos with specific posts.

Code

First of all, we need to choose a machine tag for our post entry (e.g. marcofucci:post=[post_id]) and create the get_machine_tag method in our Post model.

class Post(models.Model):
    def get_machine_tag(self):
        return "marcofucci:post=%i" % self.id

The next step is to subclass syncr.app.flickr and add one more method: syncPhotosByMachineTag.

import calendar
from datetime import datetime, timedelta
from syncr.app.flickr import FlickrSyncr

class AdvancedFlickrSyncr(FlickrSyncr):
    def syncPhotosByMachineTag(self, machine_tags, days=1):
        syncSince = datetime.now() - timedelta(days=days)
        timestamp = calendar.timegm(syncSince.timetuple())

        result = self.flickr.photos_search(machine_tags=machine_tags, per_page=500,
                                           min_upload_date=timestamp)
        page_count = result.photos[0]['pages']

        photo_list = []
        for page in range(1, int(page_count)+1):
            photo_list += self._syncPhotoXMLList(result.photos[0].photo)
            result = self.flickr.photos_search(machine_tags=machine_tags, 
                               page=page+1, per_page=500, min_upload_date=timestamp)

        return photo_list

Now we can synchronize our photos by a machine tag.

from path.to.your.subclass import AdvancedFlickrSyncr
flickr = FlickrSyncr('<api_key>', '<api_secret>')
photos = flickr.syncPhotosByMachineTag('marcofucci:post=', days=3)

Note that we don't have to specify the value, either marcofucci:post= or marcofucci: are perfect.

The final step is to display our photos using a templatetag.

from django import template

from syncr.flickr.models import Photo
from tagging.models import TaggedItem

register = template.Library()

class PhotosByMachineTagNode(template.Node):
    def __init__(self, machine_tag, varname):
        self.machine_tag, self.varname = template.Variable(machine_tag), varname

    def render(self, context):
        context[self.varname] = TaggedItem.objects.get_by_model(Photo, 
                                                  self.machine_tag.resolve(context))
        return ''

@register.tag(name="get_photos_by_machine_tag")
def get_photos_by_machine_tag(parser, token):
    """
    Syntax::

        {% get_photos_by_machine_tag [machine_tag] as [varname] %}

    Example::

        {% get_photos_by_machine_tag marcofucci:post=29 as photos %}
    """
    bits = token.contents.split()
    if len(bits) != 4:
        raise template.TemplateSyntaxError('%s tag takes exactly three arguments' 
                                                                          % bits[0])
    if bits[2] != 'as':
        raise template.TemplateSyntaxError('third argument to %s tag must be "as"'
                                                                          % bits[0])
    return PhotosByMachineTagNode(bits[1], bits[3])

Now we can use it in our view.

{% load advanced_flickr %}
...
{% get_photos_by_machine_tag post.get_machine_tag as photos %}
...

In conclusion

Just few lines of code to add machine tags to our website.

Note that you could need a moderation system to avoid spam.

Links

20 April 2009