django-mdeditor支持七牛云存储图片

时间:2024-01-27 20:14:14

由于django-mdeditor官方插件没有支持第三方存储,所以,我们只能进行修改源码的方式实现了。
本次改写即使替换了其文件,不使用七牛云也是无关紧要的,因为在存储时,去settings.py中判断是否启用七牛云存储,只有配置了七牛云相关信息才会执行,否则还是原先的方式存储在本地。
源文件路径venv\Lib\site-packages\mdeditor\views.py

使用方法

  • 修改源文件
    源文件路径venv\Lib\site-packages\mdeditor\views.py 找到该文件,将下面的代码直接复制全文替换
# -*- coding:utf-8 -*-
import os
import datetime


from django.views import generic
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from .configs import MDConfig

# TODO 此处获取default配置,当用户设置了其他配置时,此处无效,需要进一步完善
MDEDITOR_CONFIGS = MDConfig(\'default\')


class UploadView(generic.View):
    """ upload image file """

    @method_decorator(csrf_exempt)
    def dispatch(self, *args, **kwargs):
        return super(UploadView, 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\': ""
                })

        # save image
        try:
            use_qiniu = settings.MDEDITOR_USE_QINIU
            if use_qiniu:
                import qiniu,shortuuid
                from qiniu.http import ResponseInfo
                from urllib import parse
                qiniu_save = QiniuSave()
                save_name,url = qiniu_save.save(file_extension,upload_image)
                qiniu_save.dealwith_img(save_name)
                qiniu_save.cdn_flush(save_name)
            else:
                url = save_img_local(file_name, file_path, upload_image, file_extension)
        except AttributeError:
            url = save_img_local(file_name, file_path, upload_image, file_extension)

        return JsonResponse({\'success\': 1,
                             \'message\': "上传成功!",
                             \'url\': url})

    def save_img_local(self, file_name, file_path, upload_image, file_extension):
        \'\'\'将文件存储到本地\'\'\'
        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)
        return url

class QiniuSave():
    def __init__(
            self,
            access_key=settings.QINIU_ACCESS_KEY,
            secret_key=settings.QINIU_SECRET_KEY,
            bucket_name=settings.QINIU_BUCKET_NAME,
            bucket_domain=settings.QINIU_BUCKET_DOMAIN,
            ):
        self.auth = qiniu.Auth(access_key, secret_key)
        self.bucket_name = bucket_name
        self.bucket_domain = bucket_domain
        self.bucket_manager = qiniu.BucketManager(self.auth)
        
    def re_name(self,file_extension):
        name = shortuuid.uuid() +\'.\'+ file_extension
        return name


    def save(self, file_extension, content):

        if hasattr(content, \'chunks\'):
            content_str = b\'\'.join(chunk for chunk in content.chunks())
        else:
            content_str = content.read()
        name = self.re_name(file_extension)
        self._put_file(name, content_str)
        url = parse.urljoin(self.bucket_domain, name)
        return name,url

    def _put_file(self, name, content):
        token = self.auth.upload_token(self.bucket_name)
        ret, info = qiniu.put_data(token, name, content)
        if ret is None or ret[\'key\'] != name:
            raise QiniuError(info)

    # 将上传处理后的图片刷新到cdn节点,减少回源流量
    def cdn_flush(self,key):
        cdn_manager = qiniu.CdnManager(self.auth)
        domine = self.bucket_name
        need_flush_url = domine + key
        # 需要刷新的文件链接
        urls = [
            need_flush_url,
        ]
        # URL刷新链接
        refresh_url_result = cdn_manager.refresh_urls(urls)
        return

    # 进行上传的图片处理
    def dealwith_img(self,key):
        q = self.auth
        bucket_name = self.bucket_name
        # pipeline是使用的队列名称,不设置代表不使用私有队列,使用公有队列。
        # pipeline = \'your_pipeline\'
        # 要进行的转换格式操作。
        # fops = \'imageView2/0/format/webp/interlace/1\'
        fops = \'imageMogr2/format/webp\'
        # 可以对缩略后的文件进行使用saveas参数自定义命名,当然也可以不指定文件会默认命名并保存在当前空间
        saveas_key = qiniu.urlsafe_base64_encode(bucket_name + \':\' + key)
        fops = fops + \'|saveas/\' + saveas_key
        # pfop = qiniu.PersistentFop(q, bucket_name, pipeline)
        pfop = qiniu.PersistentFop(q, bucket_name)
        ops = []
        ops.append(fops)
        ret, info = pfop.execute(key, ops, 1)
        assert ret[\'persistentId\'] is not None
        return



class QiniuError(IOError):

    def __init__(self, value):
        if isinstance("Debuf Info", ResponseInfo):
            super(QiniuError, self).__init__(
                "Qiniu Response Info %s" % value
            )
        else:
            super(QiniuError, self).__init__(value)

  • 在django的settings.py中配置
# mdeitor配置
MDEDITOR_USE_QINIU = True
# qiniuyun

QINIU_ACCESS_KEY = \'七牛云账号的access_key\'
QINIU_SECRET_KEY = \'七牛云账号的secret_key\'
QINIU_BUCKET_NAME = \'七牛云的空间名称\'
QINIU_BUCKET_DOMAIN = \'七牛云空间绑定的自定义的cdn加速域名,格式:http://example.com或者:https://example.com\'