Commits

jgsogo committed 4905c35 Merge

merge time awareness

Comments (0)

Files changed (7)

flickr/__init__.py

-VERSION = (0, 3, 2)
+VERSION = (0, 3, 3)
 DEV_STATUS = '3 - Alpha'

flickr/management/commands/flickr_sync.py

                                 Photo.objects.create_from_json(flickr_user=flickr_user, photo=photo, info=info, sizes=sizes, exif=exif, geo=geo)
                             else:
                                 self.v(' - updating db', 2)
-                                Photo.objects.update_from_json(flickr_id=photo.id, photo=photo, info=info, sizes=sizes, exif=exif, geo=geo, update_tags=options.get('update_tags', False))
+                                Photo.objects.update_from_json(flickr_user=flickr_user, flickr_id=photo.id, photo=photo, info=info, sizes=sizes, exif=exif, geo=geo, update_tags=options.get('update_tags', False))
                     else:
                         self.v(' - it\'s a test, so not writing to db', 2)
                 except Exception as e:
         for photo in photos:
             self.v('- processing photo #%s "%s"' % (photo.id, photo.title), 2)
             if not options.get('test', False):
-                Photo.objects.update_from_json(flickr_id=photo.id, photo=photo)
+                Photo.objects.update_from_json(flickr_user=flickr_user, flickr_id=photo.id, photo=photo)
 
         """ Update info for outdated photos """
         self.v('- getting user photos list to update...', 1)
                     geo = get_photo_geo_json(photo_id=photo.flickr_id, token=flickr_user.token)
                     sizes = None
                     if not options.get('test', False):
-                        Photo.objects.update_from_json(flickr_id=photo.flickr_id, photo=None, info=info, sizes=sizes, exif=exif, geo=geo, update_tags=options.get('update_tags', False))
+                        Photo.objects.update_from_json(flickr_user=flickr_user, flickr_id=photo.flickr_id, photo=None, info=info, sizes=sizes, exif=exif, geo=geo, update_tags=options.get('update_tags', False))
                     else:
                         self.v(' - it\'s a test, so not writing to db', 2)
                 except Exception as e:
                         if not PhotoSet.objects.filter(flickr_id=s.id):
                             PhotoSet.objects.create_from_json(flickr_user=flickr_user, info=s, photos=photos)
                         else:
-                            PhotoSet.objects.update_from_json(flickr_id=s.id, info=s, photos=photos, update_photos=options.get('update_photos', False))
+                            PhotoSet.objects.update_from_json(flickr_user=flickr_user, flickr_id=s.id, info=s, photos=photos, update_photos=options.get('update_photos', False))
                 i += 1
                 if i % 10 == 0:
                     self.v('- %d photosets fetched, %d to go' % (i, length - i), 1)
         flickr_user = self.flickr_user
         self.v('Syncing collections', 0)
         tree = get_collections_tree_json(nsid=flickr_user.nsid, token=flickr_user.token)
-        length = len(tree)
+        length = len(tree['collections'])
         if length > 0:
             self.v('- got %d collections in root of tree for user' % length, 1)
             if not options.get('test', False):

flickr/migrations/0008_auto__add_field_flickruser_tzoffset.py

+# -*- coding: utf-8 -*-
+import datetime
+from south.db import db
+from south.v2 import SchemaMigration
+from django.db import models
+
+
+class Migration(SchemaMigration):
+
+    def forwards(self, orm):
+        # Adding field 'FlickrUser.tzoffset'
+        db.add_column('flickr_flickruser', 'tzoffset',
+                      self.gf('django.db.models.fields.CharField')(max_length=6, null=True, blank=True),
+                      keep_default=False)
+
+    def backwards(self, orm):
+        # Deleting field 'FlickrUser.tzoffset'
+        db.delete_column('flickr_flickruser', 'tzoffset')
+
+    models = {
+        'auth.group': {
+            'Meta': {'object_name': 'Group'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
+            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
+        },
+        'auth.permission': {
+            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
+            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
+        },
+        'auth.user': {
+            'Meta': {'object_name': 'User'},
+            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
+            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
+            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
+            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
+            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
+        },
+        'contenttypes.contenttype': {
+            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
+            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
+        },
+        'flickr.collection': {
+            'Meta': {'ordering': "('-date_created',)", 'object_name': 'Collection'},
+            'date_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'flickr_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}),
+            'icon': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_sync': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'auto_now_add': 'True', 'blank': 'True'}),
+            'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['flickr.Collection']", 'null': 'True'}),
+            'sets': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['flickr.PhotoSet']", 'null': 'True', 'symmetrical': 'False'}),
+            'show': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['flickr.FlickrUser']"})
+        },
+        'flickr.flickruser': {
+            'Meta': {'ordering': "['id']", 'object_name': 'FlickrUser'},
+            'flickr_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'iconfarm': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'iconserver': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'ispro': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'last_sync': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'mobileurl': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'nsid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+            'path_alias': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+            'perms': ('django.db.models.fields.CharField', [], {'max_length': '32', 'null': 'True', 'blank': 'True'}),
+            'photosurl': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'profileurl': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'realname': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'}),
+            'token': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}),
+            'tzoffset': ('django.db.models.fields.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'}),
+            'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'null': 'True', 'blank': 'True'})
+        },
+        'flickr.jsoncache': {
+            'Meta': {'object_name': 'JsonCache'},
+            'added': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'auto_now_add': 'True', 'blank': 'True'}),
+            'exception': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'exif': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'flickr_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'geo': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'info': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'sizes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'})
+        },
+        'flickr.photo': {
+            'Meta': {'ordering': "('-date_posted', '-date_taken')", 'object_name': 'Photo'},
+            'date_posted': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_taken': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_taken_granularity': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'date_updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'exif': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'exif_aperture': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+            'exif_camera': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'exif_exposure': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+            'exif_flash': ('django.db.models.fields.CharField', [], {'max_length': '20', 'null': 'True', 'blank': 'True'}),
+            'exif_focal': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True', 'blank': 'True'}),
+            'exif_iso': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'farm': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
+            'flickr_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}),
+            'geo_accuracy': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'geo_latitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+            'geo_longitude': ('django.db.models.fields.FloatField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'isfamily': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'isfriend': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'ispublic': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
+            'last_sync': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'auto_now_add': 'True', 'blank': 'True'}),
+            'license': ('django.db.models.fields.CharField', [], {'default': '0', 'max_length': '50'}),
+            'originalformat': ('django.db.models.fields.CharField', [], {'max_length': '4', 'null': 'True', 'blank': 'True'}),
+            'originalsecret': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+            'server': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
+            'show': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'url_page': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['flickr.FlickrUser']"})
+        },
+        'flickr.photodownload': {
+            'Meta': {'object_name': 'PhotoDownload'},
+            'date_downloaded': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'auto_now_add': 'True', 'blank': 'True'}),
+            'errors': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'image_file': ('django.db.models.fields.files.FileField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}),
+            'photo': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['flickr.Photo']", 'unique': 'True'}),
+            'size': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+            'url': ('django.db.models.fields.URLField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'})
+        },
+        'flickr.photoset': {
+            'Meta': {'ordering': "('-date_posted', '-id')", 'object_name': 'PhotoSet'},
+            'date_posted': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'date_updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+            'description': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
+            'farm': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
+            'flickr_id': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '50', 'db_index': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'last_sync': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'auto_now_add': 'True', 'blank': 'True'}),
+            'photos': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['flickr.Photo']", 'null': 'True', 'blank': 'True'}),
+            'primary': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True', 'blank': 'True'}),
+            'secret': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+            'server': ('django.db.models.fields.PositiveSmallIntegerField', [], {}),
+            'show': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
+            'title': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
+            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['flickr.FlickrUser']"})
+        },
+        'flickr.photosizedata': {
+            'Meta': {'unique_together': "(('photo', 'size'),)", 'object_name': 'PhotoSizeData'},
+            'height': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'photo': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'sizes'", 'to': "orm['flickr.Photo']"}),
+            'size': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
+            'source': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+            'url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
+            'width': ('django.db.models.fields.PositiveIntegerField', [], {'null': 'True', 'blank': 'True'})
+        },
+        'taggit.tag': {
+            'Meta': {'object_name': 'Tag'},
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
+            'slug': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '100'})
+        },
+        'taggit.taggeditem': {
+            'Meta': {'object_name': 'TaggedItem'},
+            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_tagged_items'", 'to': "orm['contenttypes.ContentType']"}),
+            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'object_id': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}),
+            'tag': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'taggit_taggeditem_items'", 'to': "orm['taggit.Tag']"})
+        }
+    }
+
+    complete_apps = ['flickr']
                      'photosurl': unslash(person.photosurl._content),
                      'profileurl': unslash(person.profileurl._content),
                      'mobileurl': unslash(person.mobileurl._content),
+                     'tzoffset' : person.timezone.offset,
                      #'last_sync': now(),
                      }
         return self.filter(pk=pk).update(**dict(user_data.items() + kwargs.items()))
     iconfarm = models.PositiveSmallIntegerField(null=True, blank=True)
     path_alias = models.CharField(max_length=32, null=True, blank=True)
     ispro = models.NullBooleanField()
+    tzoffset = models.CharField(max_length=6, null=True, blank=True)
 
     token = models.CharField(max_length=128, null=True, blank=True)
     perms = models.CharField(max_length=32, null=True, blank=True)
     def public(self, *args, **kwargs):
         return self.visible(ispublic=1, *args, **kwargs)
 
-    def _prepare_data(self, photo, info=None, flickr_user=None, exif=None, geo=None, **kwargs):
+    def _prepare_data(self, photo, flickr_user, info=None, exif=None, geo=None, **kwargs):
         """
         Returns a dict with all information related to a photo. As some info
         can be in several parameters, it returns data from the most especific
                         'originalformat': getattr(info_bunch, 'originalformat', ''),
                         'title': info_bunch.title._content,
                         'description': info_bunch.description._content,
-                        'date_posted': ts_to_dt(info_bunch.dates.posted),
-                        'date_taken': info_bunch.dates.taken,
+                        'date_posted': ts_to_dt(info_bunch.dates.posted, flickr_user.tzoffset),
+                        'date_taken': '%s%s' % (info_bunch.dates.taken, flickr_user.tzoffset),
                         'date_taken_granularity': info_bunch.dates.takengranularity,
-                        'date_updated': ts_to_dt(info_bunch.dates.lastupdate),
+                        'date_updated': ts_to_dt(info_bunch.dates.lastupdate, flickr_user.tzoffset),
                         'tags': info_bunch.tags.tag,
                         'ispublic': info_bunch.visibility.ispublic,
                         'isfriend': info_bunch.visibility.isfriend,
                         'originalformat': getattr(photo_bunch, 'originalformat', ''),
                         'title': photo_bunch.title,
                         'description': getattr(getattr(photo_bunch, 'description', {}), '_content', ''),
-                        'date_posted': ts_to_dt(getattr(photo_bunch, 'dateupload', '')),
+                        'date_posted': ts_to_dt(getattr(photo_bunch, 'dateupload', ''), flickr_user.tzoffset),
                         'date_taken': getattr(photo_bunch, 'datetaken', ''),
                         'date_taken_granularity': getattr(photo_bunch, 'datetakengranularity', ''),
-                        'date_updated': ts_to_dt(getattr(photo_bunch, 'lastupdate', '')),
+                        'date_updated': ts_to_dt(getattr(photo_bunch, 'lastupdate', ''), flickr_user.tzoffset),
                         'tags': getattr(photo_bunch, 'tags', ''),
                         'ispublic': photo_bunch.ispublic,
                         'isfriend': photo_bunch.isfriend,
                         'isfamily': photo_bunch.isfamily,
                         'license': photo_bunch.license,
                         }
+            if photo_info['date_taken']:
+                photo_info['date_taken'] = '%s%s' % (photo_info['date_taken'], flickr_user.tzoffset)
 
         photo_data.update(photo_info)
 
         self._add_sizes(obj, photo, sizes)
         return obj
 
-    def update_from_json(self, flickr_id, photo, info=None, sizes=None, exif=None, geo=None, **kwargs):
+    def update_from_json(self, flickr_user, flickr_id, photo, info=None, sizes=None, exif=None, geo=None, **kwargs):
         """Update a record with flickr_id"""
         update_tags = kwargs.pop('update_tags', False)
-        photo_data = self._prepare_data(photo=photo, info=info, exif=exif, geo=geo, **kwargs)
+        photo_data = self._prepare_data(photo=photo, flickr_user=flickr_user, info=info, exif=exif, geo=geo, **kwargs)
         tags = photo_data.pop('tags')
         result = self.filter(flickr_id=flickr_id).update(**dict(photo_data.items() + kwargs.items()))
         if result == 1:
             except Exception as e:
                 pass
 
-    def _prepare_data(self, info, photos, flickr_user=None, exif=None, geo=None):
+    def _prepare_data(self, info, photos, flickr_user, exif=None, geo=None):
         photoset = bunchify(info)
         photos = bunchify(photos['photoset']['photo'])
 
         data = {'flickr_id': photoset.id, 'server': photoset.server,
                   'secret': photoset.secret, 'farm': photoset.farm, 'primary': photoset.primary,
                   'title': photoset.title._content, 'description': photoset.description._content,
-                  'date_posted': ts_to_dt(photoset.date_create), 'date_updated': ts_to_dt(photoset.date_update),
+                  'date_posted': ts_to_dt(photoset.date_create, flickr_user.tzoffset), 'date_updated': ts_to_dt(photoset.date_update, flickr_user.tzoffset),
                   'photos': photos,
                   'last_sync': now(),
                   }
             data['user'] = flickr_user
         return data
 
-    def update_from_json(self, flickr_id, info, photos, update_photos=False, **kwargs):
+    def update_from_json(self, flickr_user, flickr_id, info, photos, update_photos=False, **kwargs):
         """Update a record with flickr_id"""
-        photoset_data = self._prepare_data(info=info, photos=photos, **kwargs)
+        photoset_data = self._prepare_data(info=info, photos=photos, flickr_user=flickr_user, **kwargs)
         photos = photoset_data.pop('photos')
         result = self.filter(flickr_id=flickr_id).update(**dict(photoset_data.items() + kwargs.items()))
         if result == 1 and update_photos:
         flickr_sets = PhotoSet.objects.filter(flickr_id__in=[s.id for s in sets])
         obj.sets.add(*[s.id for s in flickr_sets])
 
-    def _prepare_data(self, info, parent=None, flickr_user=None):
+    def _prepare_data(self, info, flickr_user, parent=None):
         col = bunchify(info)
         data = {'flickr_id': col.id,
                 'title': col.title, 'description': col.description,
         if flickr_user:
             data['user'] = flickr_user
         if 'date_create' in col.keys():
-            data['date_created'] = ts_to_dt(col.date_create)
+            data['date_created'] = ts_to_dt(col.date_create, flickr_user.tzoffset)
         if 'set' in col.keys():
             data['sets'] = col.set
         if 'collection' in col.keys():

flickr/templates/flickr/photo.html

+{% if photo %}
 {% if flickr_link %}<a href="{{ photo.flickr_page_url }}">{% endif %}
 <img src="{{ photo_size.source }}" width="{{ photo_size.width }}" height="{{ photo_size.height }}" alt="{{ photo.title }}" title="{{ photo.title }}" />
 {% if flickr_link %}</a>{% endif %}
+{% endif %}

flickr/templatetags/flickr_tags.py

 
 @register.inclusion_tag("flickr/photo.html")
 def flickr_photo(photo, size='medium', flickr_link=False):
+    if not photo:
+        return {}
     if size == 'large' and photo.date_posted <= datetime.datetime(2010, 05, 25):
         if photo.user.ispro:
             size = 'ori'
 from datetime import datetime
 
 
-def ts_to_dt(timestamp):
-    return datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S')
+def ts_to_dt(timestamp, offset=''):
+    return '%s%s' % (datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S'), offset)
 
 
 def unslash(url):