Django 基于腾讯云对象存储 SDK 上传图片

本贴最后更新于 1436 天前,其中的信息可能已经斗转星移

1. 前言

本篇文章将讲述如何利用腾讯云对象存储的 python SDK 上传图片,包含基础配置,原理概述和前后端搭建。

文章内容总共分为四个部分,一为环境准备,如何搭建云对象存储基于 python 的 SDK 环境;二为编写后台,如何调用 SDK 中的上传图片函数,并对图像进行进一步的处理;三为前端交互,如何利用 ajax 封装 formData 并提交至后台;最后对结果进行测试。

2. 环境准备

  • 首先进入腾讯云控制台,进入对象存储管理中心,点击存储桶-> 创建存储桶,填写名称和编辑访问权限。如果是搭建图床,权限可以设置为共有读私有写,因为图床一般需要给网站浏览者访问,但只有管理员能上传图片。
    存储桶配置
  • 创建完成以后,点击已经创建的存储桶,然后进入权限管理。
  • Policy 权限设置中删除默认的策略,然后添加策略,设置用户为所有用户,操作为所有操作,不设置可能会导致之后上传图片报 403 错误,然后保存即可。
    Policy 权限设置
  • 由于使用了腾讯云对象存储的 Python SDK,所以我们需要利用 pip 安装所需的第三方库。在命令行中输入 pip install -U cos-python-sdk-v5 安装 SDK,到此环境配置就结束了。

3. 编写后台

初始化配置信息

  • 我在 Django 项目中添加了一个 App,名称为 img_cos,在该 App 中新建了一个 config.py 文件,在其中写入了关于腾讯云存储的相关配置信息。
# appid 已在配置中移除,请在参数 Bucket 中带上 appid。Bucket 由 BucketName-APPID 组成 # 1. 设置用户配置, 包括 secretId,secretKey 以及 Region # -*- coding=utf-8 import logging import os import sys import uuid from PIL import Image from qcloud_cos import CosConfig, CosServiceError from qcloud_cos import CosS3Client from my_blog import settings logging.basicConfig(level=logging.INFO, stream=sys.stdout) secret_id = '******' # 替换为用户的 secretId secret_key = '******' # 替换为用户的 secretKey region = 'ap-shanghai' # 替换为用户的 Region token = None # 使用临时密钥需要传入 Token,默认为空,可不填 scheme = 'https' # 指定使用 http/https 协议来访问 COS,默认为 https,可不填 config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token, Scheme=scheme) # 2. 获取客户端对象 client = CosS3Client(config) host = 'https://zyk-1300089264.cos.ap-shanghai.myqcloud.com' # 存储桶访问地址 folder_path = '/article/' # 存储桶中保存图片文件夹名
  • 注意:secret_id, secret_key 和 region 都需要替换为自己存储桶对应的信息。secret_id 和 secret_key 可以到对象存储控制台的密钥管理获取,这里采用的是项目管理中的 secret_id 和 secret_key。

上传图片

  • 配置完毕之后,开始编写上传图片函数,在这里调用的 SDK 中的断点续传图片,支持断点续传,安全性更高。
  • 上传原理为:将上传的图片暂时保存至本地服务器,调用 SDK 中的上传图片方法(捕捉异常),若上传成功,则删除本地服务器上的图片,并返回图片在对象存储中的访问地址。
  • 由于图片名称可能会重复,因此采用 UUID 生成图片名称,保证名称唯一性。
    为了节约空间,调用 Pillow(没有安装 Pillow 库的小伙伴,可以先用 pip 命令安装 Pillow)中 thumbnail 方法生成缩略图。具体代码如下。
# appid 已在配置中移除,请在参数 Bucket 中带上 appid。Bucket 由 BucketName-APPID 组成 # 1. 设置用户配置, 包括 secretId,secretKey 以及 Region # -*- coding=utf-8 import logging import os import sys import uuid from PIL import Image from qcloud_cos import CosConfig, CosServiceError from qcloud_cos import CosS3Client from my_blog import settings logging.basicConfig(level=logging.INFO, stream=sys.stdout) secret_id = '******' # 替换为用户的 secretId secret_key = '******' # 替换为用户的 secretKey region = 'ap-shanghai' # 替换为用户的 Region token = None # 使用临时密钥需要传入 Token,默认为空,可不填 scheme = 'https' # 指定使用 http/https 协议来访问 COS,默认为 https,可不填 config = CosConfig(Region=region, SecretId=secret_id, SecretKey=secret_key, Token=token, Scheme=scheme) # 2. 获取客户端对象 client = CosS3Client(config) host = 'https://zyk-1300089264.cos.ap-shanghai.myqcloud.com' # 存储桶访问地址 folder_path = '/article/' # 存储桶中保存图片文件夹名 # 上传图片 def upload_file_senior(file): file_name = create_file_name(file) # 根据UUID生成文件名 root_path = os.path.join(settings.MEDIA_ROOT, 'vditor') # 生成文件上传目录 if not os.path.exists(root_path): # 判断文件上传目录是否存在 os.makedirs(root_path) # 不存在,则创建 file_path = os.path.join(root_path, file_name) with open(file_path, 'wb') as f: # 文件流将图片写入本地 for c in file.chunks(): f.write(c) file_path = compress_img(file_path, 0.75) # 压缩图片,生成缩略图 try: # 捕捉异常 response = client.upload_file( # 根据文件大小自动选择简单上传或分块上传,分块上传具备断点续传功能。 Bucket='zyk-1300089264', # 存储桶名称 LocalFilePath=file_path, # 本地图片路径 Key=folder_path + file_name, # 上传路径 PartSize=1, MAXThread=10, EnableMD5=False ) if response['ETag'] != "": os.remove(file_path) # 上传成功,删除本地图片 return host + folder_path + file_name except CosServiceError as e: print(e.get_digest_msg()) return None # 利用UUID生成文件名,防止重名 def create_file_name(file): type_name = file.name[file.name.index('.'):] # 获取文件后缀 file_name = '{}{}'.format(uuid.uuid4(), type_name) # 生成文件名 return file_name # 压缩图片 (file_path为图片路径,rate为压缩率,压缩率范围为0~1) def compress_img(file_path, rate): image = Image.open(file_path) # 获得图像 width = int(image.width * rate) # 宽 height = int(image.height * rate) # 高 image.thumbnail((width, height), Image.ANTIALIAS) # 生成缩略图 image.save(file_path) # 保存 return file_path
  • 编写视图函数,在 img_cos/views.py 中加入图片上传函数(在这里利用了
    djangorestframework 库,未安装的小伙伴可以通过 pip install djangorestframework 命令安装此库)。先从请求中获取图片,然后调用之前封装好的 SDK 上传图片方法,根据上传成功与否,封装 json 数据返回至前端,上传成功则将图片访问 URL 同时返回至前端,代码如下。
from rest_framework.decorators import api_view from rest_framework.response import Response from img_cos.config import upload_file, upload_file_senior """ 上传图片至腾讯云COS """ @api_view(['POST']) # 只允许POST请求 def upload_to_cos(request): file = request.FILES.get('smfile') # 获取上传图片 url = upload_file_senior(file) # 调用上传图片SDK,返回图片访问URL if url is None: # 上传失败 return Response({"msg": "上传失败", "code": 0}) return Response({"msg": "上传成功", "code": 1, "url": url}) # 上传成功
  • 将视图函数注册到 img_cos/urls.py 中,如下。
from django.urls import path from img_cos import views urlpatterns = [ path('upload_to_cos', views.upload_to_cos, name='upload_to_cos'), # 上传图片至腾讯云COS ]

4. 前端交互

  • 获取上传图片文件对象,利用 append()方法将其封装成 FormData,调用 ajax 上传至后台。在这里需要注意 ajax 的编写,需要添加不处理上传数据的参数。
  • 具体思路:选择要上传的图片,然后设置一个上传图片按钮,为该按钮添加点击事件,事件中调用上传图片函数,用户点击此按钮即可实现图片上传。
  • 在我的博客项目中,文章表单字段较多,而文章数据表的图片字段只保存图片访问 URL。因此,根据 ajax 上传图片返回的数据,若上传成功,将返回的图片访问 URL 写入一个隐藏的 <input> 标签,然后再提交表单。具体实现代码如下:
//上传文章贴图 function uploadArticleImg() { if ($('#img').val() === "" || $('#img').val() == null) { // 判断文件是否为空 layer.msg("请选择要上传的图片"); return; } let formData = new FormData(); formData.append('smfile', $('#img')[0].files[0]); //将文件对象写入formData $.ajax({ type: 'POST', url: '{% url 'upload_to_cos' %}', headers: {'X-CSRFToken': getCsrfToken()}, data: formData, dataType: 'JSON', contentType: false, //不处理数据 processData: false, cache: false, success: function (data) { if (data.code === 1) { layer.msg(data.msg); $("#link_url").val(data.url); // 将图片访问URL写入隐藏的input标签中 } else { layer.msg(data.msg); } }, error: function (data) { console.log(data); } }); }

5. 结果测试

  • 运行 Django 项目,测试图片上传功能,选择要上传的图片,点击上传图片按钮,观察结果。
  • 进入腾讯云控制台,查看存储桶中是否生成刚刚上传的图片。
  • 注意:如果想指定网站访问对象存储中的图片,需要在存储桶中的基础配置-> 跨域访问 CORS 设置添加自己网站的域名。
  • Python

    Python 是一种面向对象、直译式电脑编程语言,具有近二十年的发展历史,成熟且稳定。它包含了一组完善而且容易理解的标准库,能够轻松完成很多常见的任务。它的语法简捷和清晰,尽量使用无异义的英语单词,与其它大多数程序设计语言使用大括号不一样,它使用缩进来定义语句块。

    557 引用 • 675 回帖
  • Django
    47 引用 • 72 回帖 • 4 关注
  • 图床
    33 引用 • 155 回帖 • 1 关注
1 操作
zyk 在 2021-06-15 09:37:41 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...