Monday, August 30, 2010

Using Django's photologue and preserving previous image timestamps

If you've ever had to use Django's photologue module for hosting photo galleries, one of the features it exposes is the ability to add to an existing gallery by attaching .ZIP files. The function is called process_zipfile().The source for the models.py code can be found here:


The process_zipfile() works by using the Python zipfile library, and it iterates through the sorted list of entries in the zipfile.  It reads the data by invoking a function called read(), and then wraps the data around the Django ContentFile() object, which is used by ImageField and FileField objects to save the data to disk.
for filename in sorted(zip.namelist()):
                if filename.startswith('__'): # do not process meta files
                    continue
                data = zip.read(filename)
                if len(data):
                    try:
                        # the following is taken from django.newforms.fields.ImageField:
                        #  load() is the only method that can spot a truncated JPEG,
                        #  but it cannot be called sanely after verify()
                        trial_image = Image.open(StringIO(data))
                        trial_image.load()
                        # verify() is the only method that can spot a corrupt PNG,
                        #  but it must be called immediately after the constructor
                        trial_image = Image.open(StringIO(data))
                        trial_image.verify()
                    except Exception:
                        # if a "bad" file is found we just skip it.
                        continue
                    while 1:
                        title = ' '.join([self.title, str(count)])
                        slug = slugify(title)
                        try:
                            p = Photo.objects.get(title_slug=slug)
                        except Photo.DoesNotExist:
                            photo = Photo(title=title,
                                          title_slug=slug,
                                          caption=self.caption,
                                          is_public=self.is_public,
                                          tags=self.tags)
                            photo.image.save(filename, ContentFile(data))
                            gallery.photos.add(photo)
                            count = count + 1
                            break
                        count = count + 1
But what if you wanted to preserve the original datetime stamps from each image?

One way to do it is to extract the last modified time from the original file stored in the .ZIP file (using the getinfo() class and invoking it with the filename), and then using time.mktime() to convert this date_time attribute to a format that can be used by the os.utime() function.
image.file.save(file_name, ContentFile(data))

                # http://twistedmatrix.com/trac/changeset/19275/branches/dir-1951/twisted/python/zippath.py                                                            
                # Change timestamp to that set in the .ZIP file                                                                                                        
                zip = self.zfile.getinfo(file_name)
                mtime = time.mktime(zip.date_time + (0,0,0))

                os.utime(os.path.join(settings.MEDIA_ROOT, image.file.name), (mtime, mtime))
Please note, by making these changes, it's likely you will also need to include the following headers in your imports:
from django.conf import settings
import time
import zipfile

No comments:

Post a Comment