在django中使用ImageField将图片存储在bcs中
Posted on 五 05 十二月 2014 in 日常
因为像bae一类的paas平台,一般都是需要将除了代码外的文件存储到其他专门的服务中。为了使本博能上传图片,就使用了bcs,在django中,ImageField默认时存储到磁盘中,为了能上传到云上,需要自己定制storage。
定制Storage
bcs的API使用官网提供的封装好的pybcs,其他就是继承并重载FileSystemStorage。
#-*- coding: UTF-8 -*-
from django.core.files.storage import FileSystemStorage
from django.core.exceptions import SuspiciousOperation
import pybcs
import logging
import uuid
import os
pybcs.init_logging(logging.INFO)
AK = 'your AK
SK = 'your SK'
BUCKET='your bucket'
bcs = pybcs.BCS('http://bcs.duapp.com/', AK, SK, pybcs.HttplibHTTPC)
bckt = bcs.bucket(BUCKET)
class BcsStorage(FileSystemStorage):
def __init__(self, location=None, base_url=None):
super(BcsStorage, self).__init__(location, base_url)
@property
def maxSize(self):
""" max file size 2G """
return 2 * 1024 * 1024 * 1024
@property
def fileTypes(self):
""" the file types allowed """
return '*'
def makename(self, name):
oname = os.path.basename(name)
path = os.path.dirname(name)
try:
fname, hk = oname.split(".")
except Except, e:
fname, hk = oname, ''
if hk:
rname = "%s_%s.%s" % (str(uuid.uuid4()), fname, hk)
else:
rname = "%s_%s" % (str(uuid.uuid4()), fname)
name = os.path.join(path, rname)
return name
def _save(self, name, content):
hz = name.split(".")[-1]
if self.fileTypes != '*':
if hz.lower() not in self.fileTypes:
print u"不支持的文件类型%s,仅支持%s" % (hz, self.fileTypes)
raise SuspiciousOperation(u"不支持的文件类型%s,仅支持%s" % (hz, self.fileTypes))
name = self.makename(name)
if content.size > self.maxSize:
raise SuspiciousOperation(u"文件大小超过限制")
# object name must start with '/'
if name.startswith('/'):
o = bckt.object(name)
else:
o = bckt.object("/" + name)
o.put(content)
#let the object can be read by public
o.make_public()
return name
def delete(self, name):
# object name must start with '/'
if name.startswith('/'):
o = bckt.object(name)
else:
o = bckt.object("/" + name)
o.delete()
class ImageStorage(BcsStorage):
@property
def fileTypes(self):
return ['jpg', 'jpeg', 'png', 'gif']
修改pybcs
印象中应该只有一处有错,在common.py
中需要修改shorten函数:
def shorten(s, l=80):
if len(s)<=l:
return s
if hasattr(s, '__getitem__'):
return s[:l-3] + '...'
else:
return 'data...'
使用方法
在定义model时,使用ImageField,并带上参数storage=ImageStorage()
。同时需要重载delete,否则不会删除图片。
class PaperImage(models.Model): image = models.ImageField(verbose_name=ugettext(u'图片'), max_length=250, upload_to=UPLOAD_TO, storage=ImageStorage(), null=True, blank=True)
def __unicode__(self):
return u"%s" % self.image
def delete(self, using=None):
try:
self.image.storage.delete(self.image.name)
except Exception, e:
print e
pass
super(PaperImage, self).delete(using=None)
修改require,txt
我使用的bae,环境中缺少PIL包,在require.txt添加一行,写上PIL