欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前端传图片到python然后再存到七牛云

程序员文章站 2022-07-05 18:43:27
...

在网站开发中经常会遇到图片的上传和存储,最多的方案是图片存到服务器,然后数据库存地址,点开某一个页面时通过数据库的地址渲染到前端,但数据量大或者服务器吃力的情况下,图片渲染会很慢,所以最好的办法是选择云存储,以七牛云为例:

首先是前端代码(就简单来了,直接两个按钮怼上去)


```javascript
<!DOCTYPE html>
<html lang="en">
<head>
    <script src="/static/js/jquery-3.3.1.min.js" type="text/javascript" charset="utf-8"></script>
    <script src="/static/js/jquery.cookie.js"></script>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<input type="file" value="上传图片" id="upload">
<input type="button" id="checkimg" value="上传图片">


<script type="text/javascript">
    //上传图片
    $("#checkimg").click(function () {
        var img = $("#upload")[0].files[0];
        var formdata = new FormData;
        formdata.append("img", img);
        $.ajax({
                    cache: false,
                    type: "POST",
                    url: "/testone/first/",
                    data: formdata,
                    headers: {"X-CSRFToken": $.cookie('csrftoken')},
                    async: false,
                    contentType: false,
                    processData: false,
                    datatype: "json",
                    success: function (data) {
                        if (data.status_res == "success") {
                            alert("提交成功!")
                            window.location.href = "/failureProcess/failure_page/?failure_id={{ alarm.project_id }}"
                        } else if (data.status_res == "fail") {
                            alert("提交失败")
                        }
                    },
                    error: function () {
                        alert("连接失败")
                    }

                })

    });

</script>
</body>
</html>

前端传图片到python然后再存到七牛云

后台代码(django框架)

import os
from utils import Uploadimg
from django.shortcuts import render

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
path = os.path.join(BASE_DIR, r'static\js')
# Create your views here.


def first(request):
    if request.method == "POST":
        img = request.FILES.get("img")
        up = Uploadimg.UploadImg(img)
        up.upload_toqiniu()
        return render(request, "first.html")
    else:
        return render(request, "first.html")

主要的逻辑代码

import os
from . import config
from qiniu import Auth, put_file, etag

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
path = os.path.join(BASE_DIR, r'static\img')


class UploadImg(object):
    """
    上传图片到七牛云
    """

    def __init__(self, file):
        """
        初始化key
        """
        self.access_key = config.ACCESS_KEY
        self.secret_key = config.SECRET_KEY
        self.check_key(self.access_key, self.secret_key)
        self.file = file  # UPload对象
        self.check_file(self.file)  # 文件对象
        self.save_local(file)

    @staticmethod
    def check_key(access_key, secret_key):
        """
        access_key和secret_key不能为空
        """
        if not (access_key and secret_key):
            raise ValueError('秘钥错误!')

    @staticmethod
    def check_file(file):
        """
        参数必须为文件, 以是否有name属性为判断标准
        """
        if not hasattr(file, "name"):
            raise ValueError("文件错误!")

    # TODO: 获取上传空间,供选择
    def select_bucket(self):
        pass

    def upload_toqiniu(self):  # 上传实例
        localfile = path + '\\' + self.file.name
        q = Auth(self.access_key, self.secret_key)  # 实例化q,调用七牛安全机制类
        bucket_name = 'ebeauty'  # 暂时使用这个空间
        key = self.file.name
        token = q.upload_token(bucket_name, key, 3600)
        ret, info = put_file(token, key, localfile)
        assert ret['key'] == key
        assert ret['hash'] == etag(localfile)
        self.del_lcoal()

    def save_local(self, file):  # 把图片暂存到本地
        for chunk in file.chunks():
            with open(path.replace("\\", "/") + "/" + self.file.name, "wb") as f:
                f.write(chunk)

    def del_lcoal(self):  # 把本地暂存的图片删除
        for maindir, a, file_name_list in os.walk(path):
            os.remove(maindir + "\\" + self.file.name)

    def database_url(self):  # 把图片路径存入数据库
        pass

这里有几个需要注意的点:

def put_file(up_token, key, file_path, params=None,
             mime_type='application/octet-stream', check_crc=False,
             progress_handler=None, upload_progress_recorder=None, keep_last_modified=False):
    """上传文件到七牛

    Args:
        up_token:         上传凭证
        key:              上传文件名
        file_path:        上传文件的路径
        params:           自定义变量,规格参考 http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar
        mime_type:        上传数据的mimeType
        check_crc:        是否校验crc32
        progress_handler: 上传进度
        upload_progress_recorder: 记录上传进度,用于断点续传

    Returns:
        一个dict变量,类似 {"hash": "<Hash string>", "key": "<Key string>"}
        一个ResponseInfo对象
    """
    ret = {}
    size = os.stat(file_path).st_size
    # fname = os.path.basename(file_path)
    with open(file_path, 'rb') as input_stream:
        file_name = os.path.basename(file_path)
        modify_time = int(os.path.getmtime(file_path))
        if size > config._BLOCK_SIZE * 2:
            ret, info = put_stream(up_token, key, input_stream, file_name, size, params,
                                   mime_type, progress_handler,
                                   upload_progress_recorder=upload_progress_recorder,
                                   modify_time=modify_time, keep_last_modified=keep_last_modified)
        else:
            crc = file_crc32(file_path)
            ret, info = _form_put(up_token, key, input_stream, params, mime_type,
                                  crc, progress_handler, file_name,
                                  modify_time=modify_time, keep_last_modified=keep_last_modified)
    return ret, info

这是七牛云的sdk源码,可以看到他是从本地读取文件然后再上传的,所以后台接收到图片对象后要先在本地暂存一下:

    def save_local(self, file):  # 把图片暂存到本地
        for chunk in file.chunks():
            with open(path.replace("\\", "/") + "/" + self.file.name, "wb") as f:
                f.write(chunk)

等上传到七牛云之后再删除:

    def del_lcoal(self):  # 把本地暂存的图片删除
        for maindir, a, file_name_list in os.walk(path):
            os.remove(maindir + "\\" + self.file.name)

当然不删除也可以(主要是节省空间)

相关标签: 后端开发