> 文档中心 > Django结合七牛云实现对象云储存

Django结合七牛云实现对象云储存


目标

  1. 掌握 storage 类的导入方式
  2. 掌握 storage 类的操作模式
  3. 学会 查看七牛的文档,并为自己所用
  4. 掌握七牛的空间的创建、秘钥的获取

文章目录

  • 目标
  • 前言
      • 1.1 思路一
      • 1.2 思路二
  • 学习 Storage 类的使用
      • 2.1 创建存储类
      • 2.2 添加装饰器
      • 2.3 了解Storage类
      • 2.4 获取参数
      • 2.5 完整代码

前言

在Django中结合第三方实现图片、文件上传的功能,现在能够实现的思路有两个,分析如下

1.1 思路一

思路:
利用七牛现有的api,单独实现一个功能模块,来完成文件对象存储。

使用方式:
在视图中,将前端传递过来的文件数据,上传七牛,然后保存七牛返回的文件地址。

优缺点:
优点:耦合性低,易修改功能代码。逻辑简单,易操作。

1.2 思路二

思路:
继承Django的 Storage 存储类,然后在自定义的存储类中,完成上传七牛,获取文件地址的逻辑,然后以及保存的逻辑。

使用方式:
学习继承 Storage 类的要点,通过自定义逻辑封装成类,在 ImageFiled 中通过 storage 参数指向自定的类

优缺点:
能够很好的利用Django的组件,完成自定逻辑。通过Django的模型类来实现图片的增删改查,例如:自带的admin管理系统,DRF的序列化操作等。

七牛官网有写好的api,大家可以参考官网api的使用完成上述逻辑。

官方网站注册地址 https://developer.qiniu.com/

官方SDK文档 https://developer.qiniu.com/kodo/sdk/1242/python


学习 Storage 类的使用

Storage类提供了用于存储文件的标准化API,以及所有其他存储系统可以根据需要继承或覆盖的一组默认行为。

如果需要提供自定义文件存储(一个常见的示例是在某个远程系统上存储文件),则可以通过定义自定义存储类来实现。

2.1 创建存储类

您的自定义存储系统必须是 django.core.files.storage.Storage 的子类:

from django.core.files.storage import Storageclass QiNiuStorage(Storage):      pass

2.2 添加装饰器

自定义的存储类必须是 deconstructible,以便在迁移中的字段上使用它时可以序列化。 只要你的字段有自己的参数 serializable,你可以使用 django.utils.deconstruct.deconstructible 类装饰器。

from django.utils.deconstruct import deconstructiblefrom django.core.files.storage import Storage@deconstructibleclass QiNiuStorage(Storage):      pass

2.3 了解Storage类

Storage模型类 作为一个基本存储类,给我们提供一些存储系统默认拥有的方法,这些方法可以被继承或重写。

Storage模型类 提供的方法中,save() 方法 和 open() 方法中使用了未定义的 _open()以及 _save()。因此在自定义模型类时,除了自定义的方法外,我们必须继承或重写 _open()以及 _save()方法。

其他的方法如果不重写,在默认情况下,会引发 NotImplementedError异常,因此在使用时,需要将其覆盖:

  • Storage.delete()
  • Storage.exists()
  • Storage.listdir()
  • Storage.size()
  • Storage.url()

注意点:

这些方法并非都是必需的,因此可以有意省略。 碰巧的是,有可能使每个方法都未实现,而仍然可以使用存储。

举例说明

  1. 如果列出某些存储后端的内容确实很昂贵,则可以决定不实现 Storage.listdir

  2. 仅处理写入文件的后端。 在这种情况下,您将不需要实现任何上述方法。

最终,由您决定采用哪种方法。 保留一些未实现的方法将导致部分(可能已损坏)接口。

通常,您还需要使用专门为自定义存储对象设计的挂钩

from django.utils.deconstruct import deconstructiblefrom django.core.files.storage import Storage@deconstructibleclass QiNiuStorage(Storage): def __init__(self):      """初始化参数"""      pass def open(self):      """打开"""      pass def save(self):      """保存"""      pass def exists(self):      """判断文件是否存在"""      pass def delete(self):      """删除"""      pass def url(self):      """获取url地址"""      pass

2.4 获取参数

Django必须能够在没有任何参数的情况下实例化您的存储系统。 这意味着任何设置都应来自 django.conf.settings

from django.core.files.storage import Storagefrom django.conf import settings@deconstructibleclass QiNiuStorage(Storage):    """七牛云存储"""    def __init__(self, child_name): # 访问图片的根地址 self.__base_url = settings.QINIU_BASE_URL # 存储图片的空间名 self.__backet_name = settings.QINIU_BACKET_NAME # 七牛 access_key self.__access_key = settings.QINIU_ACCESS_KEY # 七牛 secret_key self.__secret_key = settings.QINIU_SECRET_KEY

2.5 完整代码

import osimport datetimeimport timefrom django.core.files.storage import Storagefrom django.utils.deconstruct import deconstructiblefrom django.conf import settingsfrom qiniu import Auth, put_data, BucketManager@deconstructibleclass QiNiuStorage(Storage):    """七牛云存储"""    def __init__(self, child_name): # 访问图片的根地址 self.__base_url = settings.QINIU_BASE_URL # 存储图片的空间名 self.__backet_name = settings.QINIU_BACKET_NAME # 七牛 access_key self.__access_key = settings.QINIU_ACCESS_KEY # 七牛 secret_key self.__secret_key = settings.QINIU_SECRET_KEY # 七牛云-构建鉴权对象 self.qiniu_server = Auth(self.__access_key, self.__secret_key) # 存储图片的子空间名 self.child_name = child_name    def _open(self, name, mode='rb'): """不需要打开文件,所以直接忽略""" pass    def _save(self, name, content): """ 存储函数 :param name: 文件名 :param content: 文件 :return: """ # 七牛云-生成上传 Token,可以指定过期时间等 token = self.qiniu_server.upload_token(self.__backet_name) # 获取文件二进制内容 file_data = content.file # 利用七牛的put_data方法上传文件内容 ret, info = put_data(     token,     self.__new_name(name, self.child_name),     file_data if isinstance(file_data, bytes) else file_data.read(), ) # 根据七牛的返回结果中的响应状态码,判断是否上传成功 if info.status_code == 200:     return ret.get("key") else:     raise Exception("上传七牛失败")    def exists(self, name): """ 判断文件是否存在,7牛云可以自动判断文件名是否以存在 所以此处返回false,告诉django上传的文件都是新的 :param name: 文件名 :return: False """ return False    def url(self, name): """ 返回文件的完整URL路径 :param name: 数据库中保存的文件名 :return: 完整的URL """ return os.path.join(self.__base_url, name)    def delete(self, name): bucket = BucketManager(self.qiniu_server) ret, info = bucket.delete(self.__backet_name, name) if ret == {} and info.status_code == 200:     return True else:     raise Exception('对象存储异常!')    @staticmethod    def __new_name(name, child_name='article'): """ 将上传的文件重新命名 :param name: 文件名 :param child_name: 子空间域名 :return: 新的文件名 """ # 获取文件后缀 file_extension = name.split('.').pop() # 获取当前的时间:年_月_日,作为二级文件夹的名字 now_time = datetime.datetime.now().strftime("%Y_%m_%d") # 因为业务量级不大,所以以时间戳为文件名字 name = int(time.time()) # 整理路径,并返回 new_name = f"file/bigevent/{child_name}/{now_time}/{name}.{file_extension}.png" return new_name