回到顶部

CONTENTS

django 图片保存至七牛云前再使用 tinify 压缩

工作中应用图片时会觉得图片能压缩又不失去显示效果,岂不美哉,果断用 tinify 来压缩图片,一来可以减小图片占用空间大小,二来放到服务器后还能节省存储空间,用于显示时也能提高图片的访问速度。

之前已经在 django 博客项目中使用 django-qiniu-storage 做过 从 ckeditor 把图片上传到七牛云

目前又闪出一个想法,在 django 中实现:图片先压缩再上传到七牛云。压缩图片使用 tinify(使用了 tinify 之后多了一套文件上传和下载过程,可能会造成上传一张图片的速度比之前慢上许多,也可能因网络问题造成失败)

第一种方法(图片 -> django -> tinify -> django -> qiniu -> 链接)

前端上传的图片到 Django 时,把图片传给 tinify, tinify 返回图片,再把 返回的图片传给 七牛云,得到图片链接。

# ckeditor_storage.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
@author: yinzhuoqun
@site: http://zhuoqun.info/
@email: yin@zhuoqun.info
@time: 2019/7/9 16:57
"""

import datetime
import uuid
import tinify
from django.core.files.storage import Storage
from qiniu import Auth, put_data
from joyoo.settings import QINIU_ACCESS_KEY, QINIU_SECRET_KEY, QINIU_BUCKET_DOMAIN_FILE, QINIU_BUCKET_NAME_FILE, \
    TINIFY_ON, TINIFY_KEY, TINIFY_KEY_USE_MAX
from logger.logger import logger


class StorageObject(Storage):
    def __init__(self):
        self.now = datetime.datetime.now()
        self.file = None

    def _new_name(self, name):
        new_name = "file/{0}/{1}.{2}".format(self.now.strftime("%Y/%m/%d"), str(uuid.uuid4()).replace('-', ''),
                                             name.split(".").pop())
        return new_name

    def _open(self, name, mode):
        return self.file

    def _to_tinify(self, content):
        if self.file.name.lower().endswith(("jpg", "png")) and TINIFY_ON:
            tinify.key = TINIFY_KEY
            try:
                tinify.validate()
            except Exception as e:
                # Validation of API key failed.
                pass
            compressions_this_month = tinify.compression_count
            logger.info("提示:tinify 本月压缩次数已使用 %s/500" % compressions_this_month)
            if compressions_this_month < TINIFY_KEY_USE_MAX:
                try:
                    file_data = tinify.from_file(content.file).to_buffer()
                except Exception as e:
                    logger.error(e)
                    file_data = content.file.read()
            else:
                file_data = content.file.read()
        else:
            file_data = content.file.read()

        return file_data

    def _save(self, name, content):
        """
        上传文件到七牛
        """
        # 构建鉴权对象
        q = Auth(QINIU_ACCESS_KEY, QINIU_SECRET_KEY)
        token = q.upload_token(QINIU_BUCKET_NAME_FILE)
        self.file = content
        # file_data = content.file.read()

        file_data = self._to_tinify(content)
        ret, info = put_data(token, self._new_name(name), file_data)

        if info.status_code == 200:
            base_url = 'http://%s/%s' % (QINIU_BUCKET_DOMAIN_FILE, ret.get("key"))
            # 表示上传成功, 返回文件名
            return base_url
        else:
            # 上传失败
            raise Exception("上传七牛失败")

    def exists(self, name):
        # 验证文件是否存在,因为我这边会去生成一个新的名字去存储到七牛,所以没有必要验证
        return False

    def url(self, name):
        # 上传完之后,已经返回的是全路径了
        return name

# settings.py

# tinify.key 图片压缩配置
TINIFY_ON = True  # 压缩开关
TINIFY_KEY = "xxxxxxxZC"  # 免费版每月 500 张图片
TINIFY_KEY_USE_MAX = 500  # 免费版每月 500 张图片

# 上传过程

[24/Sep/2019 22:35:26] "GET /static/images/favicon.ico HTTP/1.1" 200 1150
11 <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
22 <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
提示:tinify 压缩次数本月已使用 2/500
[24/Sep/2019 22:35:50] "POST /ckeditor/upload/?CKEditor=id_content&CKEditorFuncNum=1&langCode=zh-cn HTTP/1.1" 200 207

# 压缩前后比较

另外一种方法(图片 -> django -> tinify -> qiniu -> 链接)

直接改 tinify, django 收到前端传来的图片,把图片传给 tinify, tinify 直接把压缩好的图片传给七牛云,压缩的图片不用回传,tinify 返回图片地址。这种方法,目前还没搞定怎么弄,只是个想法。

^_^
请喝咖啡 ×

前一篇: How to Add Custom Action Buttons to Django Admin
下一篇: django 多级分类,一个 model 搞定
captcha
带 * 是必填项