lock = threading.Lock() # 创建一个锁的实例
上传
Q
:只有获取到用户所有信息之后才能进行上传操作Rollback
:文件保存云盘,文件信息(Tag)保存MySQLLock
:鉴于操作文件时多个请求访问同一变量,对用户的数据进行加锁
def post(self, request):
"""
用户的上传下载都需要先登录, 在这两个操作之前先进行用户身份认证
:param request: 数据携带的参数信息
:return: 文件和文件信息存储的状态
"""
# 从前端获取的数据
files = request.FILES.get("file") # 文件
filename = str(files)
author = request.POST.get("author", None)
info_id = request.POST.get("model", None)
info = PF.objects.get(id=model_id).name
if info:
new_name = create_date + "--" + filename # 用户名 + 文件名
# 在这里判断下文件格式 ==> 分开保存
try:
with transaction.atomic(): # 数据库回滚
new_file_hdf = open(FILE_PATH+ new_name, 'wb+')
# 写入本地
for chunk in files.chunks():
new_file_hdf.write(chunk)
new_file_hdf.close()
# 写入数据库
file_type = str(kl) + "qwe" + str(qwe) + "other" + str(other)
Fileinfo(carmodel=model).save()
# 从用户上传的数据中获取当前文件中的头文件
nowHDF = open(FILE_PATH+ new_name, 'rb')
header_= ""
for content in now.readlines():
try:
header_+= content.decode()
except:
continue
if content == b';#tag':
break
# 将头文件中的通道信息, 返回给前端
channel_list = re.findall(r'name str:\W+(\w+)', HDF_header, re.S)
res_dict = {
"code": 0,
"data": {
"file_save_path": FILE_PATH + new_name,
"file_old_name": filename,
"file_new_name": new_name,
"file_channel_list": channel_list
}
}
# 在这里修改当前用户数据, 上传失败则删除文件
try:
lock.acquire()
author = User.objects.get(username=author)
author.update_files_data += 1
author.save(update_fields=['update_files_data'])
lock.release()
except FileExistsError as error:
os.remove(FILE_PATH+ filename[-3:] + "/" + new_name)
res_dict = {
"code": 1,
"msg": FileExistsError
}
return HttpResponse(json.dumps(res_dict))
# 上传成功返回当前上传状态
return HttpResponse(json.dumps(res_dict))
except FileExistsError as error: # 文件操作失败:数据库回滚, 删除网盘文件
os.remove(FILE_PATH + filename[-3:] + "/" + new_name)
res_dict = {
"code": 1,
"msg": DatabaseError
}
return HttpResponse(json.dumps(res_dict))
res_dict = {
"code": 1,
"msg": "Please check the form information"
}
return HttpResponse(res_dict)
下载
文件生成器
:防止文件过大,导致内存溢出Rollback
:防止MySQL操作失败Lock
:防止操作用户变量失败
def file_down(request, pk):
"""
在这里缺少一个request的参数
:param request:封装了前端传递过来的请求
:param pk:当前用户想要下载的文件id
:return:文件下载状态
"""
user_id = request.GET.get("user_id")
file_name = F.objects.get(id=pk).file_name # 从数据库里面查询当前id的文件名
file_path = FILE_PATH+ file_name
def file_iterator(file_path, chunk_size=512):
"""
文件生成器,防止文件过大,导致内存溢出
:param file_path: 文件绝对路径
:param chunk_size: 块大小
:return: 生成器
"""
with open(file_path, mode='rb') as f:
while True:
count = f.read(chunk_size)
if count:
yield count
else:
break
try:
response = StreamingHttpResponse(file_iterator(file_path))
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename="%s"' % (urlquote(file_name))
try:
with transaction.atomic(): # 数据库回滚
# user + 1
lock.acquire() # 加锁
author = User.objects.get(id=user_id) # 当前在线的用户
author.download_files_data += 1
author.save(update_fields=['download_files_data'])
# user_ + 1
uploader_name = F.objects.get(id=pk).author # 反向查询
uploader = User.objects.get(username=uploader_name)
uploader.views += 1
uploader.save(update_fields=['views'])
lock.release() # 解锁
except:
return HttpResponse("Sorry but Data storage error")
except:
return HttpResponse("Sorry but Not Found the File")
return response
评论区