Andreas Blixt

Tagged python

This is a filtered list of entries. To see all of them, go back to the home page.

Importing your Flickr photos with Django

Friday, February 6th 2009 — Programming, Python, Django1 comment

Recently, I made my blog import updates from Flickr automatically. Since this is a pretty neat feature that is nice to have on your blog, I figured I'd share my code with you. There are a few prerequisites to using this code:

Additionally, you need Python programming experience and a basic understanding of the Django framework.

First of all, let's go through what my blog models look like.

class Entry(models.Model):
    title = models.CharField(max_length=50)
    slug = models.SlugField(max_length=50, unique_for_date='published')
    published = models.DateTimeField(auto_now_add=True)
    tags = models.ManyToManyField('Tag')
    content = models.TextField()

    class Meta:
        get_latest_by = 'published'
        ordering = ['-published']
        verbose_name_plural = 'entries'

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return '/%s/%s' % (self.published.strftime('%Y/%m/%d'), self.slug)

class Tag(models.Model):
    name = models.CharField(max_length=30, unique=True)
    display_name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.display_name

    def get_absolute_url(self):
        return '/tagged/%s' % self.name

As you can see, they're pretty straight-forward, and shouldn't be too dissimilar to your blog models. Now, let's go through the code that does the actual work!

The following code is basically just a function that will request all the recent photos of a user (specified in your settings.py file, see further below.) The photos that have not been added to your blog will be added automatically as a blog entry. I call the function whenever the front page is requested, at a maximum rate of once per hour (I used the cache module to store a global variable for one hour and only fetched the images when the variable didn't exist.)

I'm assuming you have some Python and Django experience, so the code shouldn't be too hard to customize. Feel free to contact me if you have any questions.

from datetime import datetime
from django.utils.dateformat import format
from django.utils.html import escape
from blixt import settings
from blixt.blog.models import Entry, Tag
import flickrapi

def sync_flickr():
    flickr = flickrapi.FlickrAPI(settings.FLICKR_API_KEY)

    cur_date = None
    entry = None
    page = 1
    pages = 1

    # Get/create a tag to use for Flickr update entries.
    tag, created = Tag.objects.get_or_create(
        name='photo', display_name='Photography')

    # Try to get the most recent Flickr update entry.
    try:
        flickr_updates = Entry.objects.filter(slug='flickr-update')
        most_recent = flickr_updates[0].published
    except:
        most_recent = None

    # Start a loop that will get all public photos of the user specified in the
    # settings.
    while page <= pages:
        res = flickr.people_getPublicPhotos(user_id=settings.FLICKR_USER_ID,
                                            extras='date_upload',
                                            per_page=10, page=page)
        page += 1
        pages = int(res.find('photos').get('pages'))

        # Get all <photo> elements and handle them one by one.
        photos = res.findall('photos/photo')
        for photo in photos:
            # Determine the date/time that the current photo was uploaded.
            photo_uploaded = datetime.fromtimestamp(
                int(photo.get('dateupload')))

            # If the most recently added entry is more recent than the current
            # photo, there is no need to continue because all older photos have
            # already been added.
            if most_recent and photo_uploaded <= most_recent:
                pages = 0
                break

            # Create a new entry for every unique upload date.
            if photo_uploaded.date() != cur_date:
                if entry: entry.save()
                cur_date = photo_uploaded.date()
                entry = Entry(
                    title=format(photo_uploaded, r'\F\l\i\c\k\r: M j, Y'),
                    slug='flickr-update',
                    content='')
                entry.save()
                entry.published = photo_uploaded
                entry.tags = [tag]

            # Build the HTML content for the entry.
            entry.content += settings.FLICKR_IMAGE_HTML % {
                'src': settings.FLICKR_IMAGE_SRC % photo.attrib,
                'title': escape(photo.get('title')),
                'url': settings.FLICKR_IMAGE_URL % photo.attrib
            }
    if entry: entry.save()

The following code is a snippet from my settings.py file. You'll need to replace the API key and user ID values with your own. You can customize the HTML of the generated blog entry here as well.

FLICKR_API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
FLICKR_USER_ID = '12345678@N00'
FLICKR_IMAGE_HTML = \
'<div class="thumb"><p class="image"><a href="%(url)s" title="%(title)s">' \
'<img src="%(src)s" width="75" height="75" alt="%(title)s" /></a></p>' \
'<p class="title"><a href="%(url)s" title="%(title)s">%(title)s</a></p></div>'
FLICKR_IMAGE_SRC = \
'http://farm%(farm)s.static.flickr.com/%(server)s/%(id)s_%(secret)s_s.jpg'
FLICKR_IMAGE_URL = 'http://www.flickr.com/photos/%(owner)s/%(id)s'