-- 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="图片地址")