django整合腾讯COS,实现上传图片到腾讯云
转载
安装相应的包
# 安装mdeditor
pip install django-mdeditor
# 安装腾讯云sdk
pip install -U cos-python-sdk-v5
部署mdeditor
2. 修改需要使用markdown编辑器的app的模型配置
3. 将模型注册到admin管理页面中
整合关键点理解
- django-mdeditor工作流程
django-mdeditor默认上传图片到本地,在选中图片后就会完成上传并返回相对路径到编辑器,编辑器和后端使用json通信。编辑器工作的js文件为site-packages/mdeditor/static/mdeditor/js/plugins/image-dialog/image-dialog.js,python文件为site-packages/mdeditor/views.py。大约流程为:
1. 渲染图片上传form
该form由image-dialog.js渲染,action的值为/mdeditor/uploads/?guid=1639898526591,guid是渲染时的时间戳,暂时不清楚用来干啥,在view中看不到利用这个参数的利用。
uploads相关的请求均交由这个路由,并调用views.py中的UploadView接收图片,保存后返回路径给编辑器
3. views.py的UploadView
编辑器部分相对容易理解,不过要修改编辑器界面的内容,就有点麻烦了,自定义工具栏可以通过设置来实现,但要调整其他就有点难度了,因为作者封装得太好了,压根看不懂js文件。
整合的思路
模仿编辑器的UploadView,写一个新的view,把保存图片到本地这部分改为上传到腾讯COS。
实现代码
1. 该类实现客户端初始化、上传和读取url。不过,为了规范点,先在setting文件中配置一下COS的基础信息。
2. 在视图函数中增加一个COS的类
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
import sys
import logging
class TencentCOS:
def __init__(self):
self.secret_id = settings.TENCENT_COS['secret_id']
self.secret_key = settings.TENCENT_COS['secret_key']
self.bucket = settings.TENCENT_COS['bucket']
self.region = settings.TENCENT_COS['region']
self.token = None
self.scheme = 'http'
# 初始化客户端
def client(self):
logging.basicConfig(level=logging.INFO, stream=sys.stdout)
config = CosConfig(
Reginotallow=self.region,
SecretId=self.secret_id,
SecretKey=self.secret_key,
Token=self.token,
Scheme=self.scheme
)
# 返回一个初始化的客户端,后续操作都需要基于这个客户端实例
return CosS3Client(config)
# 获取对象url
def get_obj_url(self, bucket, key):
return self.client().get_object_url(bucket, key)
# 上传文件,返回上传后的url
def upload_cos(self, image, key):
with open(image, 'rb') as fp:
response = self.client().put_object(
Bucket=self.bucket,
Body=fp,
# key是保存在cos时的名称
Key=key,
StorageClass='STANDARD',
EnableMD5=False
)
return self.get_obj_url(self.bucket, key)
1、在upload_cos方法中,参数image是要上传图片的路径,使用绝对路径上传,参数key是上传到COS后保存的名称,需要文件名+后缀,本地的图片名称可能是中文,需要自己重新组织key,等于图片重命名,然后传参给upload_cos,COS将会使用key来保存这个图片。
2、get_obj_url方法用来获取上传后图片的url,有网友按照COS的链接规律自己组织了url,这也是可以的。
class UploadCOSView(generic.View):
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super(UploadCOSView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
upload_image = request.FILES.get("editormd-image-file", None)
media_root = settings.MEDIA_ROOT
# image none check
if not upload_image:
return JsonResponse({
'success': 0,
'message': "未获取到要上传的图片",
'url': ""
})
# image format check
file_name_list = upload_image.name.split('.')
file_extension = file_name_list.pop(-1)
file_name = '.'.join(file_name_list)
if file_extension not in MDEDITOR_CONFIGS['upload_image_formats']:
return JsonResponse({
'success': 0,
'message': "上传图片格式错误,允许上传图片格式为:%s" % ','.join(
MDEDITOR_CONFIGS['upload_image_formats']),
'url': ""
})
# image floder check
file_path = os.path.join(media_root, MDEDITOR_CONFIGS['image_folder'])
if not os.path.exists(file_path):
try:
os.makedirs(file_path)
except Exception as err:
return JsonResponse({
'success': 0,
'message': "上传失败:%s" % str(err),
'url': ""
})
# 图片重命名
file_full_name = '%s_%s.%s' % (file_name,
'{0:%Y%m%d%H%M%S%f}'.format(datetime.datetime.now()),
file_extension)
# 把文件写入本地
with open(os.path.join(file_path, file_full_name), 'wb+') as file:
for chunk in upload_image.chunks():
file.write(chunk)
url = os.path.join(settings.MEDIA_URL, MDEDITOR_CONFIGS['image_folder'], file_full_name)
# 上传的文件:绝对路径
local_file = file_path + '/' + file_full_name
# 将原始文件名作为key传给COS
key = 'blog_img/' + file_name_list[0] + '.' + file_extension
# 调用COS上传文件,返回url
upload = TencentCOS().upload_cos(local_file, key)
return JsonResponse({'success': 1,
'message': "上传成功!",
'url': upload
})