# -*- coding: utf-8 -*- from __future__ import division import os import random from curtail_uuid import CurtailUUID from django.conf import settings from django.db import connection, transaction from logit import logit from rest_framework import viewsets from TimeConvert import TimeConvert as tc from account.models import UserInfo from group.models import GroupInfo, GroupPhotoInfo, GroupUserInfo, PhotoCommentInfo, PhotoThumbUpInfo from group.serializers import GroupInfoSerializer, GroupPhotoInfoSerializer, GroupUserInfoSerializer from message.models import UserMessageInfo from utils.error.errno_utils import GroupPhotoStatusCode, GroupStatusCode, GroupUserStatusCode, UserStatusCode from utils.error.response_utils import response from utils.group_photo_utils import get_current_photos from utils.page_utils import pagination from utils.redis.rgroup import (del_group_photo_thumbup_flag, get_group_info, get_group_photo_comment_list, get_group_photo_data, get_group_photo_thumbup_flag, get_group_photo_thumbup_list, get_group_photo_watchers, get_group_users_info, set_group_info, set_group_photo_comment_list, set_group_photo_data, set_group_photo_thumbup_flag, set_group_photo_thumbup_list, set_group_users_info) from utils.redis.rkeys import (GROUP_LAST_PHOTO_PK, GROUP_PHOTO_WATCHER_SET, GROUP_USERS_PASSED_SET, LENSMAN_PHOTO_HAGGLE_TIMES, LENSMAN_PHOTO_PRICE) from utils.redis.rorder import get_lensman_order_record from utils.redis.rprice import get_lensman_price_fixed from utils.sql.raw import PAI2_HOME_API from utils.storage_utils import file_save from utils.thumbnail_utils import make_thumbnail from utils.time_utils import origin_expired_stamps from utils.url_utils import img_url, share_url # db = records.Database(settings.DATABASE_URL['default']) r = settings.REDIS_CACHE @logit @transaction.atomic def group_create_api(request): """ 群组创建 """ user_id = request.POST.get('user_id', '') group_name = request.POST.get('group_name', '') group_default_avatar = int(request.POST.get('group_default_avatar', 0)) # 用户校验 try: user = UserInfo.objects.get(user_id=user_id) except UserInfo.DoesNotExist: return response(UserStatusCode.USER_NOT_FOUND) # 群组唯一标识 group_id = CurtailUUID.uuid(GroupInfo, 'group_id') # 群组记录创建 group = GroupInfo.objects.create( group_id=group_id, admin_id=user_id, group_name=group_name, group_default_avatar=group_default_avatar, group_from=GroupInfo.APP_GROUP, ) # Redis 群组数据缓存 group_info = set_group_info(group) # 群组用户记录创建 GroupUserInfo.objects.create( group_id=group_id, user_id=user_id, nickname=user.final_nickname, avatar=user.avatar, admin=True, user_status=GroupUserInfo.PASSED, passed_at=tc.utc_datetime(), ) # Redis 群组用户数据缓存 group_users = set_group_users_info(group) # Redis 群组通过集合缓存 r.sadd(GROUP_USERS_PASSED_SET % group_id, user_id) return response(200, 'Create Group Success', u'群组创建成功', { 'group_id': group_id, 'group': group_info, 'users': group_users, }) @logit def group_detail_api(request): """ 群组详情 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') return response(200, 'Get Group Detail Info Success', u'获取群组详情成功', { 'group_id': group_id, 'group': get_group_info(group_id), 'users': get_group_users_info(group_id, user_id), }) @logit def group_update_api(request): """ 群组更新 """ group_id = request.POST.get('group_id', '') admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') group_name = request.POST.get('group_name', '') group_desc = request.POST.get('group_desc', '') group_avatar = request.FILES.get('group_avatar', '') # 群组校验 try: group = GroupInfo.objects.get(group_id=group_id) except GroupInfo.DoesNotExist: return response(GroupStatusCode.GROUP_NOT_FOUND) # 权限校验 if group.admin_id != admin_id: return response(GroupStatusCode.NO_UPDATE_PERMISSION) # 群组名称更新 if group_name: group.group_name = group_name # 群组描述更新 if group_desc: group.group_desc = group_desc # 群组头像更新 if group_avatar: group.group_avatar = file_save(group_avatar, prefix='group', ext='jpeg')[0] group.save() # Redis 群组数据缓存更新 group_info = set_group_info(group) return response(200, 'Update Group Success', u'群组更新成功', { 'group_id': group_id, 'group': group_info, 'users': get_group_users_info(group_id, admin_id), }) @logit def group_list_api(request): """ 群组列表 """ user_id = request.POST.get('user_id', '') page = int(request.POST.get('page', 1)) num = int(request.POST.get('num', settings.GROUP_PER_PAGE)) group_users = GroupUserInfo.objects.filter(user_id=user_id, user_status=GroupUserInfo.PASSED).order_by('-pk') group_users, left = pagination(group_users, page, num) groups = [] for group_user in group_users: group_info = get_group_info(group_user.group_id) groups.append(group_info) if group_info else None return response(200, 'Get Group List Success', u'获取群组列表成功', { 'groups': groups, 'left': left, }) @logit def group_lock_api(request): """ 群组锁定 """ group_id = request.POST.get('group_id', '') admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') # 群组校验 try: group = GroupInfo.objects.get(group_id=group_id) except GroupInfo.DoesNotExist: return response(GroupStatusCode.GROUP_NOT_FOUND) # 权限校验 if group.admin_id != admin_id: return response(GroupStatusCode.NO_LOCK_PERMISSION) # 群组锁定 group.group_lock = True group.save() # Redis 群组数据缓存更新 set_group_info(group) return response(200, 'Lock Success', u'锁定成功') @logit def group_unlock_api(request): """ 群组解锁 """ group_id = request.POST.get('group_id', '') admin_id = request.POST.get('admin_id', '') or request.POST.get('user_id', '') # 群组校验 try: group = GroupInfo.objects.get(group_id=group_id) except GroupInfo.DoesNotExist: return response(GroupStatusCode.GROUP_NOT_FOUND) # 权限校验 if group.admin_id != admin_id: return response(GroupStatusCode.NO_UNLOCK_PERMISSION) # 群组解锁 group.group_lock = False group.save() # Redis 群组数据缓存更新 set_group_info(group) return response(200, 'Unlock Success', u'解锁成功') @logit def group_data_api(request): """ 群组数据,评论数,点赞数 """ group_id = request.POST.get('group_id', '') return response(200, 'Get Group Data Success', u'获取群组数据成功', { 'photo_datas': get_group_photo_data(group_id), }) @logit def flyimg_upload_api(request): """ 飞图上传/飞图列表 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') nickname = request.POST.get('nickname', '') photo = request.FILES.get('photo', '') current_id = int(request.POST.get('current_id', -1)) # 用户校验 try: user = UserInfo.objects.get(user_id=user_id) except UserInfo.DoesNotExist: return response(UserStatusCode.USER_NOT_FOUND) # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) if photo and r.acquire_lock('{}:{}:{}'.format(group_id, user_id, photo.name), ex=60): photo_path, ext = file_save(photo, prefix='fly', ext='jpeg') photo_thumbnail_path = photo_path.replace('.', '_thumbnail.') photo_thumbnail2_path = photo_path.replace('.', '_thumbnail2.') # 群组照片缩略图生成 # 双列: 540, 40-50K photo_w, photo_h, photo_thumbnail_w, photo_thumbnail_h = make_thumbnail( os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'), os.path.join(settings.MEDIA_ROOT, photo_thumbnail_path).replace('\\', '/'), settings.THUMBNAIL_MAX_WIDTH ) # 单列: 1080, xx-100K photo_w, photo_h, photo_thumbnail2_w, photo_thumbnail2_h = make_thumbnail( os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'), os.path.join(settings.MEDIA_ROOT, photo_thumbnail2_path).replace('\\', '/'), settings.THUMBNAIL_MAX_WIDTH2 ) # 群组照片记录创建 group_photo = GroupPhotoInfo.objects.create( group_id=group_id, user_id=user_id, nickname=nickname or user.final_nickname, avatar=user.avatar, photo_path=photo_path, photo_w=photo_w, photo_h=photo_h, photo_thumbnail_path=photo_thumbnail_path, photo_thumbnail_w=photo_thumbnail_w, photo_thumbnail_h=photo_thumbnail_h, photo_thumbnail2_path=photo_thumbnail2_path, photo_thumbnail2_w=photo_thumbnail2_w, photo_thumbnail2_h=photo_thumbnail2_h, ) # 设置群组最后一张照片PK r.set(GROUP_LAST_PHOTO_PK % group_id, group_photo.pk) return response(200, 'Flyimg Upload Success', u'飞图上传成功', get_current_photos(group_id, user_id, max(current_id, group_user.current_id))) @logit def comment_submit_api(request): """ 飞图评论提交/飞图评论列表 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') to_uid = request.POST.get('to_uid', '') photo_id = request.POST.get('photo_id', '') comment = request.POST.get('comment', '') # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(pk=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) if comment: # 群组照片评论记录创建 PhotoCommentInfo.objects.create( photo_id=photo_id, user_id=user_id, nickname=group_user.nickname, avatar=group_user.avatar, to_uid=to_uid, comment=comment, ) # 群组照片评论数更新 group_photo.comment_num += 1 group_photo.save() # Redis 群组照片数据缓存 set_group_photo_data(group_id) # Redis 群组照片评论列表缓存刷新 set_group_photo_comment_list(photo_id) r.sadd(GROUP_PHOTO_WATCHER_SET % photo_id, user_id) # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 # 照片所有者(评论/点赞)不给自己提醒 if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id) and group_photo.user_id != user_id: UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=group_photo.user_id, group_id=group_photo.group_id, photo_id=group_photo.pk, msg_type=UserMessageInfo.COMMENT, msg_title=u'评论', msg_content=comment, ) # 给所有关注者(评论/点赞)发送提醒 watchers = get_group_photo_watchers(photo_id) # 从关注者中移除该(评论/点赞)者 watchers.discard(user_id) # 从关注者中移除该照片所有者 watchers.discard(group_photo.user_id) for watcher in watchers: UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=watcher, group_id=group_photo.group_id, photo_id=group_photo.pk, msg_type=UserMessageInfo.COMMENT, msg_title=u'评论', msg_content=comment, ) return response(200, 'Comment Success', u'评论成功', { 'comments': get_group_photo_comment_list(photo_id), }) @logit def thumbup_submit_api(request): """ 飞图点赞提交 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(pk=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) # user_id 是否点赞 photo_id if get_group_photo_thumbup_flag(photo_id, user_id): return response(GroupPhotoStatusCode.DUPLICATE_THUMB_UP) # 群组照片点赞记录创建/更新 photo_thumbup, created = PhotoThumbUpInfo.objects.get_or_create( photo_id=photo_id, user_id=user_id, ) photo_thumbup.nickname = group_user.nickname photo_thumbup.avatar = group_user.avatar photo_thumbup.thumbup = True photo_thumbup.save() # Redis 群组照片点赞数据缓存 set_group_photo_thumbup_flag(photo_id, user_id) # 群组照片点赞数更新 group_photo.thumbup_num += 1 group_photo.save() # Redis 群组照片数据缓存 set_group_photo_data(group_id) # Redis 群组照片点赞列表缓存刷新 set_group_photo_thumbup_list(photo_id) r.sadd(GROUP_PHOTO_WATCHER_SET % photo_id, user_id) # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 # 照片所有者(评论/点赞)不给自己提醒 if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id) and group_photo.user_id != user_id: UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=group_photo.user_id, group_id=group_photo.group_id, photo_id=group_photo.pk, msg_type=UserMessageInfo.THUMBUP, msg_title=u'点赞', msg_content=u'点赞', ) # 给所有关注者(评论/点赞)发送提醒 watchers = get_group_photo_watchers(photo_id) # 从关注者中移除该(评论/点赞)者 watchers.discard(user_id) # 从关注者中移除该照片所有者 watchers.discard(group_photo.user_id) for watcher in watchers: UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=watcher, group_id=group_photo.group_id, photo_id=group_photo.pk, msg_type=UserMessageInfo.THUMBUP, msg_title=u'点赞', msg_content=u'点赞', ) return response(200, 'Thumbup Success', u'点赞提交成功', { 'thumbup': True, 'thumbups': get_group_photo_thumbup_list(photo_id), }) @logit def thumbup_list_api(request): """ 飞图点赞列表 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') return response(200, 'Get Thumbup List Success', u'获取点赞列表成功', { 'thumbup': get_group_photo_thumbup_flag(photo_id, user_id), # user_id 是否点赞 photo_id 'thumbups': get_group_photo_thumbup_list(photo_id), # 群组照片点赞列表 }) @logit def thumbup_cancel_api(request): """ 飞图点赞取消 """ group_id = request.POST.get('group_id', '') user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') # 群组用户校验 try: group_user = GroupUserInfo.objects.get(group_id=group_id, user_id=user_id, user_status=GroupUserInfo.PASSED) except GroupUserInfo.DoesNotExist: return response(GroupUserStatusCode.GROUP_USER_NOT_FOUND) # 群组照片校验 try: group_photo = GroupPhotoInfo.objects.get(pk=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) # user_id 是否点赞 photo_id if not get_group_photo_thumbup_flag(photo_id, user_id): return response(GroupPhotoStatusCode.THUMB_UP_NOT_FOUND) # 群组照片点赞取消 photo_thumbup, created = PhotoThumbUpInfo.objects.get_or_create( photo_id=photo_id, user_id=user_id, ) photo_thumbup.thumbup = False photo_thumbup.save() # Redis 群组照片点赞数据移除 del_group_photo_thumbup_flag(photo_id, user_id) # 群组照片点赞数更新 group_photo.thumbup_num -= 1 group_photo.save() # Redis 群组照片数据缓存 set_group_photo_data(group_id) # Redis 群组照片点赞列表缓存刷新 set_group_photo_thumbup_list(photo_id) # 判断群组照片发布者是否已经被管理员移除/主动退出,如若移除/退出,则不给发布者提醒 if r.sismember(GROUP_USERS_PASSED_SET % group_photo.group_id, group_photo.user_id): UserMessageInfo.objects.create( from_uid=user_id, from_nickname=group_user.nickname, from_avatar=group_user.avatar, to_uid=group_photo.user_id, group_id=group_photo.group_id, photo_id=group_photo.pk, msg_type=UserMessageInfo.THUMBUP, msg_title=u'取消点赞', msg_content=u'取消点赞', ) # 群组照片点赞列表 photo_thumbups = PhotoThumbUpInfo.objects.filter( photo_id=photo_id, thumbup=True, ) return response(200, 'Thumbup Cancel Success', u'点赞取消成功', { 'thumbup': False, 'thumbups': [thumbup.thumbup_info for thumbup in photo_thumbups], }) @logit def pai2_home_api(request): """ 首页照片信息 """ user_id = request.POST.get('user_id', '') page = int(request.POST.get('page', 1)) num = int(request.POST.get('num', settings.PAI2_HOME_PER_PAGE)) # 执行原生 SQL 语句,获取首页照片列表 cursor = connection.cursor() cursor.execute(PAI2_HOME_API.format( user_id=user_id, offset=0, rows=settings.PAI2_HOME_MAX_ROWS, )) rows = cursor.fetchall() # 使用 records 执行原生 SQL 语句,获取首页照片列表 # rows = db.query(PAI2_HOME_API.format( # user_id=user_id, # offset=0, # rows=settings.PAI2_HOME_MAX_ROWS, # )).all() # 首页照片分页 rows, left = pagination(rows, page, num) # 首页照片信息 rows = [{ 'group_id': row[0], 'group_name': row[1], 'group_default_avatar': row[2], 'group_avatar': row[3], 'group_from': row[4], 'photo_id': row[5], 'photo_url': img_url(row[6]), 'photo_w': row[7], 'photo_h': row[8], 'photo_thumbnail_url': img_url(row[9]), 'photo_thumbnail_w': row[10], 'photo_thumbnail_h': row[11], 'photo_thumbnail2_url': img_url(row[12]), 'photo_thumbnail2_w': row[13], 'photo_thumbnail2_h': row[14], 'photo_share_url': share_url(row[5]), # Warning: Index of This Line is 5 'user_id': row[15], 'nickname': row[16], 'avatar': row[17], 'comment_num': row[18], 'thumbup_num': row[19], 'photo_from': row[20], 'session_id': row[21], 'created_at': row[22], 'origin_expired_stamps': origin_expired_stamps(row[23], row[15]), 'thumbup': get_group_photo_thumbup_flag(row[5], user_id), 'porder': get_lensman_order_record(row[5], user_id) if row[20] == GroupPhotoInfo.SESSION_GROUP else {}, } for row in rows] # rows = [dict(row) for row in rows] # [row.update({ # 'photo_url': img_url(row['photo_path']), # 'photo_thumbnail_url': img_url(row['photo_thumbnail_path']), # 'photo_thumbnail2_url': img_url(row['photo_thumbnail2_path']), # 'photo_share_url': share_url(row['photo_id']), # 'thumbup': get_group_photo_thumbup_flag(row['photo_id'], user_id), # 'porder': get_lensman_order_record(row['photo_id'], user_id) if row['photo_from'] == GroupPhotoInfo.SESSION_GROUP else {}, # }) for row in rows] return response(200, 'Get Home Data Success', u'获取首页数据成功', { 'photos': rows, 'left': left, }) @logit def lensman_photo_price(request): """ 摄影师照片价格获取 """ user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') photo_type = request.POST.get('photo_type', 'nomark') # nomark for 去除水印, origin for 获取高清图 lensman_photo_price_key = LENSMAN_PHOTO_PRICE % (user_id, photo_id, photo_type) # Redis 获取存储的价格 price = int(r.get(lensman_photo_price_key) or 0) if price: # Redis 获取存储的砍价次数 haggle_times = r.incr(LENSMAN_PHOTO_HAGGLE_TIMES % (user_id, photo_id, photo_type)) # 判断砍价是否已经超过次数 if haggle_times <= settings.LENSMAN_PHOTO_HAGGLE_MAX_TIMES: # 砍掉的价格 haggle_price = random.choice([50, 100]) # 砍价后的价格 price = max(price - haggle_price, 1) # Redis 设置新价格 r.set(lensman_photo_price_key, price) else: try: group_photo = GroupPhotoInfo.objects.get(pk=photo_id) except GroupPhotoInfo.DoesNotExist: return response(GroupPhotoStatusCode.GROUP_PHOTO_NOT_FOUND) # 获取摄影师定价 price = get_lensman_price_fixed(group_photo.user_id).get(photo_type, 999) # Redis 设置新价格 r.set(lensman_photo_price_key, price) return response(200, 'Get Price Success', u'获取价格成功', { 'price': price }) @logit def lensman_photo_bought(request): """ 摄影师照片已购买 """ user_id = request.POST.get('user_id', '') photo_id = request.POST.get('photo_id', '') return response(200, 'Get Bought Data Success', u'获取购买数据成功', { 'porder': get_lensman_order_record(photo_id, user_id) }) class GroupInfoViewSet(viewsets.ModelViewSet): queryset = GroupInfo.objects.all().order_by('-pk') serializer_class = GroupInfoSerializer class GroupUserInfoViewSet(viewsets.ModelViewSet): queryset = GroupUserInfo.objects.all().order_by('-pk') serializer_class = GroupUserInfoSerializer class GroupPhotoInfoViewSet(viewsets.ModelViewSet): queryset = GroupPhotoInfo.objects.all().order_by('-pk') serializer_class = GroupPhotoInfoSerializer # Only Once Function def refresh_thumbnail(): """ 刷新缩略图 """ photos = GroupPhotoInfo.objects.filter(status=True) for photo in photos: try: photo_path = photo.photo_path photo_thumbnail_path = photo_path.replace('.', '_thumbnail.') photo_thumbnail2_path = photo_path.replace('.', '_thumbnail2.') # 群组照片缩略图生成 # 双列: 540, 40-50K photo_w, photo_h, photo_thumbnail_w, photo_thumbnail_h = make_thumbnail( os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'), os.path.join(settings.MEDIA_ROOT, photo_thumbnail_path).replace('\\', '/'), settings.THUMBNAIL_MAX_WIDTH ) # 单列: 1080, xx-100K photo_w, photo_h, photo_thumbnail2_w, photo_thumbnail2_h = make_thumbnail( os.path.join(settings.MEDIA_ROOT, photo_path).replace('\\', '/'), os.path.join(settings.MEDIA_ROOT, photo_thumbnail2_path).replace('\\', '/'), settings.THUMBNAIL_MAX_WIDTH2 ) photo.photo_w = photo_w photo.photo_h = photo_h photo.photo_thumbnail_path = photo_thumbnail_path photo.photo_thumbnail_w = photo_thumbnail_w photo.photo_thumbnail_h = photo_thumbnail_h photo.photo_thumbnail2_path = photo_thumbnail2_path photo.photo_thumbnail2_w = photo_thumbnail2_w photo.photo_thumbnail2_h = photo_thumbnail2_h photo.save() except Exception as e: pass return 'Refresh Thumbnail OK' def statistic_thumbnail_size(pfrom): """ 统计缩略图大小 :param pfrom: 0 for APP_GROUP, 1 for SESSION_GROUP, -1 for ALL :return: """ if pfrom == -1: photos = GroupPhotoInfo.objects.filter(status=True) else: photos = GroupPhotoInfo.objects.filter(photo_from=pfrom, status=True) photo_count = photos.count() photo_size = 0 photo_thumbnail_size = 0 photo_thumbnail2_size = 0 for photo in photos: photo_size += os.path.getsize(os.path.join(settings.MEDIA_ROOT, photo.photo_path).replace('\\', '/')) photo_thumbnail_size += os.path.getsize(os.path.join(settings.MEDIA_ROOT, photo.photo_thumbnail_path).replace('\\', '/')) photo_thumbnail2_size += os.path.getsize(os.path.join(settings.MEDIA_ROOT, photo.photo_thumbnail2_path).replace('\\', '/')) print '>>> Photo Size: %.3f KB' % (photo_size / 1024 / photo_count) print '>>> Photo Thumbnail Size: %.3f KB' % (photo_thumbnail_size / 1024 / photo_count) print '>>> Photo Thumbnail2 Size: %.3f KB' % (photo_thumbnail2_size / 1024 / photo_count) return 'Statistic Thumbnail Size OK'