storage.py:

2016-11-23  本文已影响25人  seventhboy

-- coding: UTF-8 --

from os import environ

debug = not environ.get("APP_NAME", "") #判断sae环境
from django.utils.translation import ugettext as _
from django.core.files.storage import FileSystemStorage
from django.core.exceptions import ImproperlyConfigured, SuspiciousOperation
from django.conf import settings
import time,os,uuid,random,unicodedata,StringIO
from django.core.files.base import ContentFile
if not debug:
import sae
import tempfile
import sae.storage
from PIL import Image #这里是关键,sae加载Image的方式
else:
import Image

class SaeAndNotSaeStorage(FileSystemStorage):
"""
这是一个支持sae和本地django的FileStorage基类
修改存储文件的路径和基本url
"""
def init(self, location=settings.MEDIA_ROOT, base_url=settings.MEDIA_URL):
super(SaeAndNotSaeStorage, self).init(location, base_url)

def get_valid_name(self, name):
"""
这个方法用于验证文件名,我这里的处理方法是去掉中文,我没有找到支持中文名的方法,欢迎补充
"""

name = unicodedata.normalize('NFKD', name).encode('ascii', 'ignore')

处理中文文件名sae不支持

if not debug:
try:
if 1:

去掉中文

name = unicodedata.normalize('NFKD', name).encode('ascii', 'ignore')
else:
for k in name:
if self.is_chinese(k):
name = "wszw%s"%random.randint(0,100)
except Exception,e:
name = "%s.jpg"%type(name)

end

return super(SaeAndNotSaeStorage, self).get_valid_name(name)

@property
def maxsize(self):
return 1010241024#文件2M--sae限制只能传2M,单个文件,据说是10M,其实只有2M

@property
def filetypes(self):
return []

def makename(self,name):

取一个不重复的名字,sae会把重名覆盖

oname = os.path.basename(name)
path = os.path.dirname(name)

首先判断是否需要重命名---也就是说不想改名字的就加这个前缀

if oname.find("mine")==0:
oname = oname.replace("mine","")
name = os.path.join(path, oname)
return name

end---首先判断是否需要重命名

try:
fname, hk = oname.split(".")
except Exception,e:
fname, hk = oname, ''
if hk:
rname = "%s_%s.%s"%(random.randint(0,10000), fname,hk)
else:
rname = "%s_%s"%(random.randint(0,10000), fname)
name = os.path.join(path, rname)

end

return name

def _save(self, name, content):
"""
可以判断上传哪些文件
"""
hz = name.split(".")[-1]

类型判断

if self.filetypes!='*':
if hz.lower() not in self.filetypes:
raise SuspiciousOperation(u"不支持的文件类型,支持%s"%self.filetypes)

end

name = self.makename(name)

大小判断

if content.size > self.maxsize:
raise SuspiciousOperation(u"文件大小超过限制")

end

保存

if not debug:
s = sae.storage.Client()
if hasattr(content, '_get_file'):#admin入口
ob = sae.storage.Object(content._get_file().read())
else:#view入口(ContentFile)
ob = sae.storage.Object(content.read())
url =s.put('image', name, ob) #注意这里的media,是sae-storage上的domain名
return name
else:
return super(SaeAndNotSaeStorage, self)._save(name, content)

end--保存

def delete(self,name):
"""
sae的存储空间很宝贵,所有我们在删除图片数据库记录的时候也需要删除图片
"""
if not debug:
s = sae.storage.Client()
try:
s.delete('image', name)
except Exception,e:
pass
else:
super(SaeAndNotSaeStorage, self).delete(name)

class ImageStorage(SaeAndNotSaeStorage):
"""
实现一个ImageField的Storage
"""
@property
def maxsize(self):
return 210241024#文件2M

@property
def filetypes(self):
return ['jpg','jpeg','png','gif']

class FileStorage(SaeAndNotSaeStorage):
@property
def maxsize(self):
return 1010241024#文件5M

@property
def filetypes(self):
return "*"

def makename(self, name):

return name

class ThumbStorage(ImageStorage):
"""
缩略图-------这个非常关键,处理后的图片在sae上怎么保存,关键就在StringIO
"""
def _save(self, name, content):

处理

image = Image.open(content)
image = image.convert('RGB')
image.thumbnail((50, 50), Image.ANTIALIAS)

output = StringIO.StringIO()
image.save(output,'JPEG')
co = ContentFile(output.getvalue())
output.close()

end

return super(ThumbStorage, self)._save(name, co)

调用的model.py:
from storage import ImageStorage,FileStorage,ThumbStorageiconUrl = models.ImageField(upload_to=upload_path_handler, storage=ImageStorage(),verbose_name="图片地址")

上一篇下一篇

猜你喜欢

热点阅读