-文件管理——清理废弃文件功能

-文件管理——文件来源(导出、用户上传)
pull/3/MERGE
李强 2021-03-27 10:49:29 +08:00
parent 7525e6cf2c
commit e900deb2b4
11 changed files with 126 additions and 13 deletions

View File

@ -20,6 +20,7 @@ class CustomModelSerializer(ModelSerializer):
# 添加默认时间返回格式
create_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
update_datetime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S", required=False, read_only=True)
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
def __init__(self, instance=None, data=empty, request=None, **kwargs):
super().__init__(instance, data, **kwargs)

View File

@ -43,6 +43,7 @@ class SaveFileFilter(django_filters.rest_framework.FilterSet):
文件管理 简单过滤器
"""
name = django_filters.CharFilter(lookup_expr='icontains')
type = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = SaveFile

View File

@ -16,6 +16,7 @@ class SaveFile(CoreModel):
type = CharField(max_length=32, verbose_name="文件类型", null=True, blank=True)
size = CharField(max_length=64, verbose_name="文件大小", null=True, blank=True)
address = CharField(max_length=16, verbose_name="存储位置", null=True, blank=True) # 本地、阿里云、腾讯云..
source = CharField(max_length=16, verbose_name="文件来源", null=True, blank=True) # 导出、用户上传.
oss_url = CharField(max_length=200, verbose_name="OSS地址", null=True, blank=True)
status = BooleanField(default=True, verbose_name="文件是否存在")
file = FileField(verbose_name="文件URL", upload_to=files_path, )

View File

@ -120,7 +120,7 @@ class ConfigSettingsCreateUpdateSerializer(CustomModelSerializer):
# ================================================= #
# ************** 参数设置 序列化器 ************** #
# ************** 文件管理 序列化器 ************** #
# ================================================= #
class SaveFileSerializer(CustomModelSerializer):
@ -136,7 +136,7 @@ class SaveFileSerializer(CustomModelSerializer):
class SaveFileCreateUpdateSerializer(CustomModelSerializer):
"""
字典详情 创建/更新时的列化器
文件管理 创建/更新时的列化器
"""
file_url = serializers.CharField(source='file.url', read_only=True)
@ -146,6 +146,7 @@ class SaveFileCreateUpdateSerializer(CustomModelSerializer):
self.validated_data['size'] = files.size
self.validated_data['type'] = files.content_type
self.validated_data['address'] = '本地存储'
self.validated_data['source'] = '用户上传'
instance = super().save(**kwargs)
# 进行判断是否需要OSS上传
return instance
@ -228,7 +229,6 @@ class LoginInforSerializer(CustomModelSerializer):
"""
登录日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = LoginInfor
@ -239,7 +239,6 @@ class ExportLoginInforSerializer(CustomModelSerializer):
"""
导出 登录日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = LoginInfor
@ -255,7 +254,6 @@ class OperationLogSerializer(CustomModelSerializer):
"""
操作日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = OperationLog
@ -266,7 +264,6 @@ class ExportOperationLogSerializer(CustomModelSerializer):
"""
导出 操作日志 简单序列化器
"""
creator_name = serializers.SlugRelatedField(slug_field="username", source="creator", read_only=True)
class Meta:
model = OperationLog

View File

@ -42,5 +42,7 @@ urlpatterns = [
re_path('celery_log/clean/', CeleryLogModelViewSet.as_view({'delete': 'clean_all', })),
# 导出定时日志
re_path('celery_log/export/', CeleryLogModelViewSet.as_view({'get': 'export', })),
# 清除废弃文件
re_path('clearsavefile/', SaveFileModelViewSet.as_view({'post': 'clearsavefile', })),
]
urlpatterns += router.urls

View File

@ -1,3 +1,6 @@
import os
from django.conf import settings
from django.db.models import Q
from rest_framework.request import Request
@ -16,6 +19,7 @@ from ..system.serializers import DictDataSerializer, DictDataCreateUpdateSeriali
OperationLogSerializer, ExportOperationLogSerializer, ExportLoginInforSerializer, CeleryLogSerializer, \
ExportCeleryLogSerializer
from ..utils.export_excel import export_excel_save_model
from ..utils.file_util import get_all_files, remove_empty_dir, delete_files
from ..utils.response import SuccessResponse
@ -149,6 +153,26 @@ class SaveFileModelViewSet(CustomModelViewSet):
search_fields = ('configName',)
ordering = '-create_datetime' # 默认排序
def clearsavefile(self, request: Request, *args, **kwargs):
"""
清理废弃文件
:param request:
:param args:
:param kwargs:
:return:
"""
# 获取废弃文件列表
file_list = get_all_files(os.path.join(settings.MEDIA_ROOT, 'system'))
queryset_files = [os.path.join(os.path.join(settings.MEDIA_ROOT) + os.sep, ele) for ele in
list(self.get_queryset().values_list('file', flat=True))]
delete_list = list(set(file_list) - set(queryset_files))
# 进行文件删除操作
delete_files(delete_list)
# 递归删除空文件
remove_empty_dir(os.path.join(settings.MEDIA_ROOT, 'system'))
return SuccessResponse(msg=f"成功清理废弃文件{len(delete_list)}")
class MessagePushModelViewSet(CustomModelViewSet):
"""

View File

@ -134,7 +134,9 @@ def export_excel_save_model(request, field_data, data, FilName):
savefile.type = 'application/vnd.ms-excel'
savefile.size = os.path.getsize(os.path.join(settings.MEDIA_ROOT, file_rul))
savefile.address = '本地存储'
savefile.source = '导出'
savefile.creator = request.user
savefile.dept_belong_id = getattr(request.user, 'dept_id', None)
savefile.modifier = request.user.username
savefile.save()
return SaveFileSerializer(savefile).data

View File

@ -0,0 +1,48 @@
"""
封装文件操作:
递归读取所有文件目录形成列表
递归删除空目录
批量删除文件
"""
import os
def get_all_files(targetDir):
"""
递归读取所有文件目录形成列表
:param targetDir:
:return:
"""
files = []
listFiles = os.listdir(targetDir)
for i in range(0, len(listFiles)):
path = os.path.join(targetDir, listFiles[i])
if os.path.isdir(path):
files.extend(get_all_files(path))
elif os.path.isfile(path):
files.append(path)
return files
def remove_empty_dir(path):
"""
递归删除空目录
:param path:
:return:
"""
for root, dirs, files in os.walk(path, topdown=False):
if not files and not dirs:
os.rmdir(root)
def delete_files(delete_list: list):
"""
批量删除文件
:param delete_list:
:return:
"""
for file_path in delete_list:
try:
os.remove(file_path)
except(FileNotFoundError):
pass

View File

@ -1,4 +1,5 @@
asgiref==3.3.1
celery==5.0.5
Django==2.2.16
django-cors-headers==3.7.0
django_celery_beat==2.2.0

View File

@ -79,8 +79,8 @@
"vue-template-compiler": "2.6.12"
},
"engines": {
"node": ">=8.9",
"npm": ">= 3.0.0"
"node": ">=12.0",
"npm": ">= 6.0.0"
},
"browserslist": [
"> 1%",

View File

@ -14,7 +14,7 @@
<el-form-item label="文件类型" prop="type">
<el-input
v-model="queryParams.type"
placeholder="请输入文件类型(待完善)"
placeholder="请输入文件类型"
clearable
size="small"
style="width: 240px"
@ -72,8 +72,33 @@
<el-table-column label="文件类型" width="150" align="center" prop="type"/>
<el-table-column label="文件大小" width="90" align="center" prop="size"/>
<el-table-column label="存储位置" align="center" prop="address"/>
<el-table-column label="文件本地地址" align="center" prop="file" :show-overflow-tooltip="true"/>
<el-table-column label="OSS地址" align="center" prop="oss_url" :show-overflow-tooltip="true"/>
<el-table-column label="文件来源" align="center" prop="source"/>
<el-table-column label="文件本地地址" align="center" prop="file" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-document-copy"
@click="CopyFileUrl(scope.row.file)"
v-if="scope.row.file"
></el-button>
&nbsp;
<span>{{ scope.row.file }}</span>
</template>
</el-table-column>
<el-table-column label="OSS地址" align="center" prop="oss_url" :show-overflow-tooltip="true">
<template slot-scope="scope">
<el-button
size="mini"
type="text"
icon="el-icon-document-copy"
@click="CopyFileUrl(scope.row.oss_url)"
v-if="scope.row.oss_url"
></el-button>
&nbsp;
<span>{{ scope.row.oss_url }}</span>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="create_datetime" width="160">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.create_datetime) }}</span>
@ -218,9 +243,9 @@
type: "warning"
}).then(function () {
return clearSaveFile();
}).then(() => {
}).then((values) => {
this.getList();
this.msgSuccess("删除成功");
this.msgSuccess(values.msg);
})
},
/** 完成按钮 */
@ -229,6 +254,17 @@
this.open = false;
this.$refs.saveFile.fileList = []
},
CopyFileUrl(values){
const input = document.createElement('input');
document.body.appendChild(input);
input.setAttribute('value', values);
input.select();
if (document.execCommand('copy')) {
document.execCommand('copy');
this.msgSuccess("复制成功");
}
document.body.removeChild(input);
}
}
}