AberSheeran
Aber Sheeran
I know nothing except the fact of my ignorance.

文件自动同步七牛云

起笔自
所属文集: 杂记
共计 1819 个字符
落笔于

由于服务器的带宽与存储问题,图片不得不上七牛云了。

模型

以下是一个很简单的图片模型,之前我有写过一篇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函数,从七牛云的储存空间里删除对应的文件。

如果你觉得本文值得,不妨赏杯茶
清理Django的迁移文件
Python文件的热重载