由于服务器的带宽与存储问题,图片不得不上七牛云了。
模型
以下是一个很简单的图片模型,之前我有写过一篇Django多图片上传,所以在此不赘述如何处理图片上传部分了。
class Image(models.Model):
file = models.ImageField(upload_to='upload/', verbose_name="路径")
message = models.ForeignKey(Message, on_delete=models.CASCADE, verbose_name="所属消息")
class Meta:
verbose_name = u"图片"
verbose_name_plural = u"图片"
配置七牛云
首先在项目里执行pipenv install qiniu
来安装七牛云提供的Python库。
在Django项目的settings.py
里,配置以下代码
from qiniu import Auth
QINIU = Auth(
access_key='YOUR ACCESS KEY',
secret_key='YOUR SECRET KEY'
)
BUCKET_NAME = "YOUR BUCKET NAME"
其中两个key需要自己去七牛云 - 密钥管理里看。而bucket的名字就是所需要自动同步的对象储存的储存空间名。
配置信号
import os
from django.conf import settings
from django.db.models.signals import pre_delete, post_save
from django.dispatch import receiver
from qiniu import BucketManager
from qiniu import put_file, etag
from .models import Image
@receiver(post_save, sender=Image)
def update_image(sender, instance, **kwargs):
path = str(instance.file)
if not path:
return
filepath = os.path.join(settings.MEDIA_ROOT, path)
token = settings.QINIU.upload_token(settings.BUCKET_NAME, path, 3600)
ret, info = put_file(token, path, filepath)
assert ret['key'] == path
assert ret['hash'] == etag(filepath)
os.remove(filepath)
# 初始化BucketManager
manager = BucketManager(settings.QINIU)
@receiver(pre_delete, sender=Image)
def delete_image(sender, instance, **kwargs):
path = str(instance.file)
if not path:
return
ret, info = manager.delete(settings.BUCKET_NAME, path)
# 无视删除错误
# assert ret == {}
利用Django的信号机制,可以在图片储存到本地之后,自动调用update_image
函数上传图片到七牛云并且删除本地的备份,如果上传失败,本地图片将不会被删除。
如果图片的模型从数据库中删除,会自动调用delete_image
函数,从七牛云的储存空间里删除对应的文件。