大家好,我是橘子,今天来记录ANT+VUE3+DJANGO的文件上传的设置。
前端部分
我没搞清楚要怎么直接通过upload的提交事件来提交我们的CSRFToken,所以我通过beforeUpload进行拦截提交,然后在自己进行提交操作。
前端这边流程大概是这样:
①设置一个UPLOAD按钮
②给按钮绑定fileList和before-upload
③在before-upload里面拦截提交事件,自己做后续的提交
// template
// 设置按钮
<a-form-item label="点击上传课题成果" name="xuncha_is">
<a-upload v-model:file-list="fileList" :before-upload="beforeUpload">
<a-button>
<upload-outlined></upload-outlined>
上传监管报告
</a-button>
</a-upload>
</a-form-item>
// script
// 定义文件对象
interface FileItem {
uid: string;
name?: string;
status?: string;
response?: string;
url?: string;
preview?: string;
originFileObj?: any;
file: string | Blob;
}
// setup
//拦截提交事件,将文件数据填入List
const fileList = ref<FileItem[]>([]);
const beforeUpload = (file: FileItem) => {
fileList.value = [...fileList.value, file];
return false;
};
//确认提交按钮回调,如果不要这个按钮可以直接在beforUpload里面调用
const onSubmit = () => {
const data = new FormData();
fileList.value.forEach((file: FileItem) => {
file.status = 'uploading'
// 这里的操作和官方例子不同,可以测试一下,我用官方的例子无法识别
data.append('files', file.originFileObj);
});
// 添加token
data.append('token', String(token))
// 新建一个修改头部的axios,因为我其他的数据是通过URLSearchParams提交的,识别的头不同
const upload_ax = axios.create({
withCredentials: true,
headers: {
'Content-Type': 'multipart/form-data'
}
})
//用新的对象提交
upload_ax.post('http://127.0.0.1:3000/fxc_upload_keti_file/', data)
.then((response) => {
// 处理数据完成情况
let done_str = response.data.done
let done_list = done_str.split('|')
let m_file = fileList.value.find(myObj => myObj.name === done_list[0])
if (m_file) {
m_file.status = 'done'
}
}
)
后台部分
def upload_keti_file(request):
ret_dict = {}
print('课题文件上传接口')
if request.POST:
print(request.FILES)
file_list = request.FILES.getlist('files')
# 有些代码用get只能获取到最后一个文件的数据,需要用getlist,具体操作可以看MultiValueDict的相关操作
# request.FILES.get('file')
done_list_str = ''
if not file_list:
print(301)
ret_dict['code'] = '301'
ret_dict['msg'] = '文件获取错误'
else:
print(200)
print(file_list)
save_path = os.path.join(UPLOAD_PATH, datetime.datetime.now().date().strftime("%Y%m"))
if not os.path.exists(save_path):
os.makedirs(save_path)
for file in file_list:
destination = open(os.path.join(save_path, file.name), 'wb+') # 打开特定的文件进行二进制的写操作
for chunk in file.chunks(): # 分块写入文件
destination.write(chunk)
destination.close()
done_list_str += file.name + '|'
ret_dict['code'] = '200'
ret_dict['msg'] = '上传文件成功'
ret_dict['done'] = done_list_str
return HttpResponse(json.dumps(ret_dict, ensure_ascii=False), content_type="application/json")
我是懒惰的llsxily,今天大家就直接看代码吧,也没啥技术含量。你可以叫我橘子。
Update:20230216
现在的antd5.x已经不用file.originFileObj,需要直接调用file。
fileList.forEach((file) => {
data.append('files', file);
});