Vue+Django 处理上传的文件代码部分:
Vue部分:
<el-upload
ref="upload"
:auto-upload='false'
:multiple='false'
:before-upload="beforeUpload"
:limit="1"
accept=".txt"
action=""
type="file"
:http-request="chooseFile">
<el-button class="reportFilebtn"> 选择文件</el-button>
</el-upload>
method
beforeUpload(file) {
const fileSuffix = file.name.substring(file.name.lastIndexOf(".") + 1);
const whiteList = ["txt"];
if (whiteList.indexOf(fileSuffix) === -1) {
this.$message.error('上传文件只能是txt格式');
return false;
}
},
chooseFile(file) {
this.$refs.upload.clearFiles()
this.file = file.file
// if(JSON.stringify(file) != '{}'){
var forms = new FormData()
var configs = {
headers:{'Content-Type':'multipart/form-data'}
}
forms.append('errList',this.uartlogForm.errList)
forms.append('uartFile',this.file)
this.logCheckStation = []
uartLogTool(forms, configs).then(response => {
})
},
Api.js
export const uartLogTool = (params)=>{
return axios.post(`tool/uartParseErr`,params)
}
Django部分
def uartParseErr(request):
if request.method == 'POST':
response = {}
uartFileData = request.FILES.get('uartFile', None)
dutErrStr = request.POST.get('dutErrList','ERROR,Fail,Not Found').strip(',,')
smokeyErrStr = request.POST.get('smokeyErrList','Not Found,All errors').strip(',,')
#使用该方法缓存InMemoryFiles至Media/tmp文件夹,然后只需要把路径复制过去即可解析
storageTempPath = default_storage.save('tmp/{}'.format(uartFileData), ContentFile(uartFileData.read()))
uartFilePath = os.path.join(settings.MEDIA_ROOT,storageTempPath)
with open(uartFilePath,'r',encoding="utf-8") as file:
log_data = file.read()
# 处理文件的代码省略
try:
response['uartData'] = dict_uart_log_data
response['stationID'] = STATION_ID
response['overlayVer'] = OVERLAY_VERSION
response['msg'] = 'success'
response['error_num'] = 0
except Exception as e:
#print(traceback.format_exc(limit=1))
response['msg'] = str(e)
response['error_num'] = 1
#删除之前缓存的文件,避免内存臃肿
os.remove(uartFilePath)
return JsonResponse(response)
Django后台上传文件
1)Django上传文件配置,在settings配置:
# 配置上传文件目录
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
2)配置映射url
from django.views.static import serve
from django.conf import settings
urlpatterns = [
...,
url(r'^media/(?P<path>.*)', serve, {"document_root": settings.MEDIA_ROOT}, name='media')
]
3)使用ivew上传组件实现上传头像 前端操作
<Upload
ref="upload"
type="drag"
:before-upload="handleUpload" // 上传之前的回调函数 返回true才表示成功
:on-success="uploadSuccess" // 上传成功的回调函数
:on-error="uploadError" // 错误回调函数
:on-exceeded-size="handleMaxSize" // 上传文件大小回调函数
:max-size="2048" // 设置文件最大
:data="data" // 其他上传数据
:format="['jpg', 'png', 'jpeg']" // 设置上传格式
:on-format-error="handleFormatError2" // 判断格式
:action="api+'/api/uploadAvatar'" // 上传的地方(接口)
>
<div style="padding: 20px 0">
<Icon type="ios-cloud-upload" size="52" style="color: #3399ff"></Icon>
<p>Click or drag picture here to upload</p>
</div>
</Upload>
handleUpload(file) {
return true;
},
uploadSuccess(res) {
//上传成功
this.$Message.info(res.result.msg);
if (res.result.code == 200) {
this.$http
.userLogin(this.author, this.pwd, this.getCookie("csrftoken"))
.then(resp => {
if (resp.result.code === "200") {
var obj = {
username: this.author,
password: this.pwd,
avatar: resp.result.avatar
};
sessionStorage.setItem("user", JSON.stringify(obj));
}
});
}
this.reload();
},
handleFormatError2() {
this.$Message.error("文件格式不正确,请上传jpg、jpeg、png格式文件");
},
uploadError(error) {
this.$Message.info(error);
},
handleMaxSize(file) {
this.$Notice.warning({
title: "超出文件大小限制",
desc: "文件 " + file.name + " 太大,不能超过 2M。"
});
},
4)后台接收前端文件操作
def upload_avatar(request):
file = request.FILES.get('file', '') # 获取文件
author = request.POST.get('author', '') # 获取用户
img_addr = '%s/person/%s' % (settings.MEDIA_ROOT, file.name) # 指定文件上传路径及文件名
# 写入文件
with open(img_addr, 'wb') as f:
for f_img in file.chunks():
f.write(f_img)
user = UserProfile.objects.get(Q(username=author) | Q(email=author)) # 获取用户对象
user.portrait = 'person/'+file.name # 修改用户头像
user.save() # 保存
data = {'code': '200', 'msg': '修改头像成功'}
return JsonResponse({'result': data})
下载文件
from django.http import StreamingHttpResponse
import os
from django.utils.encoding import escape_uri_path # 处理文件名文中文下载失败
def file_iterator(filename, chunk_size=512):
with open(filename, 'rb') as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break
# 下载文件
def download_file_text(request, file_name):
name = file_name.split('/')[-1] # 显示在弹出对话框中的默认的下载文件名
file_local = 'media/'+file_name # 要下载的文件路径
if not os.path.exists(file_local):
return HttpResponse('File not found 404')
response = StreamingHttpResponse(file_iterator(file_local))
response['Content-Type'] = 'application/octet-stream'
response['Content-Length'] = os.path.getsize(file_local)
response['Content-Disposition'] = 'attachment;filename="{}"'.format(escape_uri_path(name))
return response
同名文件覆盖
1)在app中新建stroage.py文件
from django.core.files.storage import FileSystemStorage
from django.conf import settings
import os
class OverwriteStorage(FileSystemStorage):
def get_available_name(self, name, max_length=None):
if self.exists(name): # 上传文件同名则移除
os.remove(os.path.join(settings.MEDIA_ROOT, name))
return name
2)在models.py中引入
from interface.storage import OverwriteStorage
class DocumentDownload(models.Model):
tag = models.ForeignKey(DocumentTag, related_name='tag_documents', verbose_name='文件类型', on_delete=models.CASCADE, null=True, blank=True)
filename = models.CharField(max_length=100, verbose_name='文件名称')
document = models.FileField(upload_to='documents', default='', verbose_name='文件', storage=OverwriteStorage())
version = models.CharField(max_length=50, default='1.0.0', verbose_name='版本号')
# equip_updated = models.BooleanField(default=True, verbose_name="根据设备可更新")
updated = models.BooleanField(default=True, verbose_name="全局可更新文件")
add_time = models.DateTimeField(verbose_name='添加时间', default=datetime.now)
# 多对一(文件--类别)
'''
一个文件类型下面的所有文件:
tag.tag_documents.all()
'''
class Meta:
db_table = 'document_download'
unique_together = ('tag', 'filename',) # 联合唯一约束
verbose_name = '文件管理'
verbose_name_plural = verbose_name
def __str__(self):
return str(self.document)
这样就能在上传文件时同名文件覆盖。
删除数据库数据对应删除本地文件
1)在对应models文件
from django.db.models.signals import pre_delete
from django.dispatch.dispatcher import receiver
@receiver(pre_delete, sender=DocumentDownload)
def global_delete(sender, instance, **kwargs):
# Pass false so FileField doesn't save the model.
instance.document.delete(False) # False 表示model不保存
pre_delete.connect(global_delete, sender=DocumentDownload) # 关联信号