目录
前言
上传功能
后端代码
前端代码
下载功能
后端代码
前端代码
前言
首先我要实现的页面效果是这样的
当点击上传文件按钮,弹出上传文件的弹出框,可以上传多个文件,点击确定后才正式开始上传
点击右侧下载按钮,可以直接下载文件。
上传功能
后端代码
settings.py
MEDIA_ROOT = os.path.join(BASE_DIR, '../upload')
MEDIA_URL = '/upload/'
这段代码表示你上传的文件都会放在你项目根目录的upload文件夹下。
views.py
@api_view(('POST',))
@renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def upload_list(request):
# 如果项目根目录没有upload文件夹,会自动给你创建一个
folder_path = settings.MEDIA_ROOT
if not os.path.exists(folder_path):
os.makedirs(folder_path)
files = request.FILES.getlist('file')
for file in files:
# 这三行代码就是上传文件的代码
f = open(settings.MEDIA_ROOT + "/" + file.name, mode='wb')
for chunk in file.chunks():
f.write(chunk)
# 这段代码是我要网数据库里存的一些文件信息,如果不存库的话不用写
size = file.size
suffix = file.content_type
createUser = request.user
filePath = settings.MEDIA_URL + file.name
name = file.name
# 上传完文件记得要关闭
# 需要注意的一点,如果f.close()这句代码之前,上传文件之后有报错,那你文件是一直被占用的状态,删除也删不掉,所以一定要做好代码顺序
f.close()
# 往数据库里存文件信息
Filemanage.objects.create(size=size, suffix=suffix, create_user=createUser, file_path=filePath, name=name)
return JsonResponse(OrderedDict([
('results', {})
], code=status.HTTP_200_OK))
前端代码
<el-upload
class="upload-demo"
ref="upload"
action=""
:auto-upload="false"
:http-request="upload"
:before-upload="beforeAvatarUpload"
multiple
>
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
:ref="upload":必须要写,因为我们是手动上传方式。
:auto-upload="false":这里我设置的不自动上传,如果你没有确定按钮,点击一起上传的需求,那你就把值变为ture,你选完文件后会自动上传。
:http-request="upload":覆盖默认的上传行为,可以自定义上传的实现。
:before-upload="beforeAvatarUpload":上传文件之前的钩子,一般用于限制上传文件大小和类型。
multiple:多文件上传。
methods: {
beforeAvatarUpload(file) {
const isLt2M = file.size / 1024 / 1024 < 200;
if (!isLt2M) {
this.$message.error('上传头像图片大小不能超过2MB!');
}
return isLt2M;
},
upload(param) {
const formData = new FormData()
formData.append('file', param.file)
mail.uploadFile(formData).then(response => {
console.log('上传图片成功')
this.$refs.upload.clearFiles()
}).catch(response => {
console.log(response)
this.$refs.upload.clearFiles()
});
},
}
下载功能
后端代码
def download(request, nid):
# 通过前台传来的id查出文件名
row_object = Filemanage.objects.filter(id=nid).first()
# 文件的相对路径
file_path = '/upload/' + row_object.name
# 打开文件
with open(settings.MEDIA_ROOT + "/" + row_object.name, 'rb') as f:
response = HttpResponse(f.read())
# 设置Content-Disposition头以强制浏览器下载文件
file_name = os.path.basename(file_path)
response["Content-Type"] = "application/octet-stream"
response['Content-Disposition'] = f'attachment; filename="{file_name}"'
return response
前端代码
<el-button
v-if="permissionList.del"
size="small"
type="success "
@click="download(row)"
>{{ "下载" }}</el-button>
methods: {
download(row) {
this.loading = true;
// 这块是我封装的axios请求,请求时要带着responseType: 'blob',我会在下面放上我的代码
file.requestDownload(row.id).then((response) => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', row.name);
document.body.appendChild(link);
link.click();
})
.catch((e) => {
console.log(e)
});
},
}
requestDownload(id) {
return request({
url: '/tool/download/' + id + '/',
method: 'get',
responseType: 'blob'
})
}