首先新建一个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. 基于对象的实时空间音频渲染丨Dev for Dev 专栏

    本文为「Dev for Dev 专栏」系列内容,作者为声网音频算法工程师 李嵩. 随着元宇宙概念的引入,空间音频这项技术慢慢映入大家的眼帘.关于空间音频的基础原理,我们做过一期科普视频 -- 「空间音 ...

  2. Java项目是不是分布式,真有那么重要吗?

    大家好,我是3y啊. 大概不知道从什么时候,「微服务」「分布式」这两个词又再次频繁出现在我的视线里. 「微服务」「分布式」在我刚毕业的时候还是比较关注的,那时候还入门了一把SpringCloud,写了 ...

  3. StyleGAN 生成 AI 虚拟人脸,再也不怕侵犯肖像权

    目录 什么是 StyleGAN 如何使用 StyleGAN 下载项目 修改项目 MSVC 运行项目 运行结果 什么是 StyleGAN GAN 是机器学习中的生成性对抗网络,目标是合成与真实图像无法区 ...

  4. [C++STL教程]6.bitset是什么?和bool有什么区别?零基础都能看懂的入门教程

    之前我们介绍过vector, queue, stack,map,set,今天我们介绍另外一个stl容器:bitset. 作者:Eriktse 简介:19岁,211计算机在读,现役ACM银牌选手力争以通 ...

  5. 聊聊Spring扩展点BeanPostProcessor和BeanFactoryPostProcessor

    介绍 今天聊一聊spring中很重要的两个扩展点BeanPostProcessor和BeanFactoryPostProcessor,spring之所以如次强大,是因为它提供了丰富的功能给我们使用,但 ...

  6. 面对AI的兴起,从人类发展到个人发展,普通人应当如何抉择?

    这一周被各种 AI 卷的不行,从 ChatGPT 4.0 上线到百度文心一言发布会,再到微软的 Microsoft 365 Copilot. 网上有很多人.公众号吐嘈百度,而晓衡接触到的圈子还有一些不 ...

  7. TypeScript 学习笔记 — 自定义类型:部分属性可选,反选 key,求对象交差并补集等(十三)

    目录 将部分属性变为可选属性 根据值的类型 反选 key 写法一:基础原理写法,使用不同的内置类型,Pick 和 Omit 写法二:基础原理写法,使用 Pick 内置类型 + 传参的方式 写法三:使用 ...

  8. MINIO搭建单机以及集群

    MINIO简介 Minio是Apache License v2.0下发布的对象存储服务器.它与Amazon S3云存储服务兼容.它最适合存储非结构化数据,如照片,视频,日志文件,备份和容器/VM映像. ...

  9. 0001 嵌入式开发带你从小白到大佬系列之——Linux开发环境搭建—Windows-VMware-Ubuntu环境配置

    如文章标题,我们安装的Linux开发环境是:Windows-VMware-Ubuntu环境 配置,即在windows系统下安装VMware虚拟机,之后在VMware中配置安装Linux系统的常用发行版 ...

  10. SSM整合的所有配置(配置类)

    导入依赖坐标pom.xml <dependencies> <dependency> <groupId>junit</groupId> <artif ...