首先新建一个MyStorage.py,自定义Storage类

  

from io import BytesIO

from django.core.files.storage import Storage
from django.conf import settings from utils.minioClient import go_upload_file, go_delete_file, go_upload_file_have_size
from utils.tools import img_bucket class MinioStorage(Storage):
"""
自定义文件存储系统
"""
def __init__(self):
pass def _open(self, name, mode='rb'):
"""
用于打开文件
:param name: 要打开的文件的名字
:param mode: 打开文件方式
:return: None
"""
pass def _save(self, name, content):
"""
用于保存文件
:param name: 要保存的文件名字
:param content: 要保存的文件的内容
:return: None
"""
# print(name)
name = name.replace('\\', '/')
# ret = go_upload_file(BytesIO(content.read()), bucket=img_bucket, path_name=name)
ret = go_upload_file_have_size(BytesIO(content.read()), content.size, bucket=img_bucket, path_name=name)
assert ret == 1, '文件上传失败'
path = '/' + name
return path def delete(self, name):
# im = get_file_path(instance.img)
# print(name)
# name = str(name).split('/')[-1]
ret = go_delete_file(bucket=img_bucket, path_name=str(name))
# print(ret) def url(self, name):
"""
返回name所指文件的绝对URL
:param name: 要读取文件的引用
:return:
"""
host = settings.MINIOHTTP + settings.MINIOWEBHOST + ':' + settings.MINIOWEBPORT
return host + "/" + img_bucket + name def exists(self, name):
"""
检查文件存在
"""
return False

这么实现 def url(self, name)这个函数,需要在Minio后台将 bucket 权限设置为public,就是开放的所有人皆可访问

Minio实现上传文件,新建minioClient.py

  

import copy
import os from django.conf import settings
from minio import Minio MINIO_CONF = {
'endpoint': settings.MINIOHOST + ':' + settings.MINIOPORT,
'access_key': settings.MINIOUSER,
'secret_key': settings.MINIOPWD,
'secure': False
} client = Minio(**MINIO_CONF) def get_file_size(file):
"""
获取文件大小
file: bytes
return: int
"""
file.seek(0, os.SEEK_END)
return file.tell()
# im = io.BytesIO(file)
# return im.getbuffer().nbytes def go_upload_file(file, bucket='media', path_name=''):
"""
上传文件
"""
try:
# print(path_name)
# print(type(file))
file_len = get_file_size(copy.copy(file))
# print(file_len)
client.put_object(bucket_name=bucket, object_name=path_name, data=file, length=file_len)
return 1
except Exception as e:
print(e)
return 0 def go_upload_file_have_size(file, size, bucket='media', path_name=''):
"""
上传文件,已有文件大小
"""
try:
client.put_object(bucket_name=bucket, object_name=path_name, data=file, length=size)
return 1
except Exception as e:
print(e)
return 0 def go_delete_file(bucket='media', path_name=''):
"""
删除文件
"""
try:
# print(bucket, path_name)
client.remove_object(bucket_name=bucket, object_name=path_name)
return 1
except Exception as e:
print(e)
return 0 def go_delete_file_list(bucket='media', path_name_list=[]):
"""
删除文件列表
未实现,据说需要删除完遍历结果
"""
try:
ret = client.remove_objects(bucket, path_name_list, bypass_governance_mode=False)
print(ret)
return 1
except Exception as e:
print(e)
return 0 def get_file_url(bucket='media', path_name=''):
"""
获取文件url
"""
try:
url = client.presigned_get_object(bucket_name=bucket, object_name=path_name)
return url
except Exception as e:
print(e)
return None def get_file_path(path):
path = path.split('/')[2:]
final_path = '/'.join(path)
return final_path

新建一个tools.py

  

import datetime
import os
import random
import time img_type_list = ['.jpg', '.png', '.jpeg']
img_bucket = 'media' def get_secret(request):
"""
获取加密的key
"""
return request.META.get('HTTP_AUTHORIZATION') or 'wchime' def get_time_string():
"""
:return: 20220525140635467912
:PS :并发较高时尾部随机数增加
"""
time_string = str(datetime.datetime.fromtimestamp(time.time())).replace("-", "").replace(" ", "").replace(":","").replace(".", "") + str(random.randint(100, 999))
return time_string def split_file_type(file):
"""
对文件名切割,获取名字和类型
"""
file_li = os.path.splitext(file)
return file_li[0], file_li[1] if __name__ == '__main__':
im = 'a.png'
s = split_file_type(im)
print(s)

我的models.py

  

class TestImg(models.Model):
name = models.CharField(verbose_name="名字", max_length=256)
img = models.ImageField(upload_to='zzz')

新建一个视图文件

from io import BytesIO

from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from django.utils.decorators import method_decorator
from rest_framework import status, serializers
from rest_framework.response import Response

from ani import models
from utils.decorators import request_decrypt
from utils.myView import MyPagination, MyView, MixinGetList, MixinPostCreateModel, MixinPutUpdateModel, \
MixinDeleteDestroyModel
from utils.tools import split_file_type, img_type_list, get_time_string, img_bucket

class TestImgSerializer(serializers.ModelSerializer):
class Meta:
model = models.TestImg
fields = '__all__'

def create(self, validated_data):
res = models.TestImg.objects.create(**validated_data)
return res

def update(self, instance, validated_data):

instance.name = validated_data.get('name')
if validated_data.get('img', False) is not False:
instance.img = validated_data.get('img')
instance.save()
return instance

@method_decorator(request_decrypt, name='get')
class TestImgView(MyView, MixinGetList):
queryset = models.TestImg.objects.all()
serializer_class = TestImgSerializer
all_serializer_class = TestImgSerializer
filter_class = ['name__icontains']
pagination_class = MyPagination
lookup_field = 'id'
ordeing_field = ('-id',)

def post(self, request, *args, **kwargs):
data = request.data
file_content = data.get('file').read()
file_name = get_time_string() + '.png'
# print(file_content)
content_file = ContentFile(file_content, file_name)
# print(content_file)
data['img'] = content_file

serializer_class = TestImgSerializer
serializer = serializer_class(data=data)
# print(serializer.is_valid())
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)

def put(self, request, *args, **kwargs):
data = request.data
try:
instance = self.queryset.get(id=data.get(self.lookup_field))
except Exception:
return Response({'state': 'fail', 'msg': '未找到该数据'}, status=status.HTTP_400_BAD_REQUEST)
file = data.get('file')
if file:
file_content = file.read()
file_name = get_time_string() + '.png'
# print(file_content)
content_file = ContentFile(file_content, file_name)
# print(content_file)
data['img'] = content_file
if instance.img:
default_storage.delete(instance.img)
serializer_class = TestImgSerializer
serializer = serializer_class(instance=instance, data=data, partial=True)
# print(serializer.is_valid())
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)

def delete(self, request, *args, **kwargs):
try:
instance = self.queryset.get(id=request.data.get(self.lookup_field))
except Exception:
return Response({'state': 'fail', 'msg': '未找到数据'}, status=status.HTTP_400_BAD_REQUEST)
default_storage.delete(instance.img)
instance.delete()
return Response({'state': 'success', 'msg': '删除成功'}, status=status.HTTP_204_NO_CONTENT)

在settings.py中加上

DEFAULT_FILE_STORAGE = 'utils.MyStorage.MinioStorage'

整个项目文件结构

postman调用的结果

Django自定义storage上传文件到Minio的更多相关文章

  1. django 自定义存储上传文件的文件名

    一.需求: Django实现自定义文件名存储文件 使文件名看起来统一 避免收到中文文件导致传输.存储等问题 相同的文件也需要使用不同的文件名 二.实现思路: 思路: 生成14位随机字母加数字.后10位 ...

  2. Django和Ueditor自定义存储上传文件的文件名

    django台后默认上传文件名 在不使用分布式文件存储系统等第三方文件存储时,django使用默认的后台ImageField和FileField上传文件名默认使用原文件名,当出现同名时会在后面追加下随 ...

  3. django实现分片上传文件

    目标:利用django实现上传文件功能 1,先设置路由系统 urls.py from django.conf.urls import url,include from django.contrib i ...

  4. Django之用户上传文件的参数配置

    Django之用户上传文件的参数配置 models.py文件 class Xxoo(models.Model): title = models.CharField(max_length=128) # ...

  5. element-ui上传组件,通过自定义请求上传文件

    记录使用element-ui上传组件,通过自定义请求上传文件需要注意的地方. <el-upload ref="uploadMutiple" :auto-upload=&quo ...

  6. django + dropzone.js 上传文件

    1.dropzone.js http://www.dropzonejs.com/ dropzone.js是一个可预览\可定制化的文件拖拽上传,实现AJAX异步上传文件的工具 2.dropzone.js ...

  7. Django session cookie 上传文件、详解

    session 在这里先说session 配置URL from django.conf.urls import patterns, include, url from django.contrib i ...

  8. 基于element ui 实现七牛云自定义key上传文件,并监听更新上传进度

    借助上传Upload 上传组件的 http-request 覆盖默认的上传行为,可以自定义上传的实现 <el-upload multiple ref="sliderUpload&quo ...

  9. Taro 微信小程序 上传文件到minio

    小程序前端上传文件不建议直接引用minio的js npm包,一来是这个包本身较大,会影响小程序的体积,二来是ak sk需要放到前端存储,不够安全,因此建议通过请求后端拿到签名数据后上传. 由于小程序的 ...

  10. 1. Django系列之Django与ajax上传文件

    html代码如下: <div class="form-group"> <label for="exampleInputFile">附件上 ...

随机推荐

  1. 针对于Sql server突然连接不到服务器的解决方法

    问题叙述 点击连接之后,总是会弹出一个错误弹窗: 方法解决 快捷键Win+R,输入services.msc,进入到服务界面: 找到SQL 代理(DEV) 将手动打开改成自动 再连接试一次 连上啦! ( ...

  2. D3和X6

    D3 版本 d3已经更新到v7版本,中文文档只更新到v4版本,存在部分api不适用和过时问题 使用d3-darge插件布局,插件适配d3版本为v5,近年未更新 API 使用darge中setNode和 ...

  3. 马志强:语音识别技术研究进展和应用落地分享丨RTC Dev Meetup

    本文内容源自「RTC Dev Meetup 丨语音处理在实时互动领域的技术实践和应用]的演讲分享,分享讲师为寰语科技语音识别研究主管马志强. 01 语音识别技术现状 1.语音成为万物互联时代人机交互关 ...

  4. Django笔记四之字段属性

    这篇笔记介绍的 field options,也就是 字段的选项属性. 首先,关于 model,是数据库与 python 代码里的一个映射关系,每一个 model 是django.db.models.M ...

  5. NetCore 使用 Swashbuckle 搭建 SwaggerHub

    什么是SwaggerHub? Hub 谓之 中心, 所以 SwaggerHub即swagger中心. 什么时候需要它? 通常, 公司都拥有多个服务, 例如商品服务, 订单服务, 用户服务, 等等, 每 ...

  6. yolov5训练自己的数据集

    1.安装cuda 可以先看看自己的 显卡信息,支持哪个cuda版本 cuda下载地址:https://developer.nvidia.com/cuda-toolkit-archive 我的RTX30 ...

  7. 你真的懂synchronized锁?

    1. 前言 synchronized在我们的程序中非常的常见,主要是为了解决多个线程抢占同一个资源.那么我们知道synchronized有多种用法,以下从实践出发,题目由简入深,看你能答对几道题目? ...

  8. Windows 与 虚拟机VirtualBox 共享挂载

    在自己的电脑上安装了虚拟机后,经常会有需要把Windows这边的文件或文件夹拷贝到虚拟机上,简单记录一下. 如下图,设备--共享文件夹 然后在Windows上创建共享文件夹 执行命令 sudo mkd ...

  9. ARM Cortex-M4|非常好用的一种串口收发方式

    在这里分享项目中我经常使用的一种串口收发方式:阻塞发送 + 接收中断 +空闲中断 + 环形队列 项目代码地址:www.baidu.com 一.简介 串口发送使用最简单的阻塞发送方式,一般来说都是接收的 ...

  10. TypeScript 学习笔记 — 数组常见的类型转换操作记录(十四)

    获取长度 length type LengthOfTuple<T extends any[]> = T["length"]; type A = LengthOfTupl ...