" name="sm-site-verification"/>
侧边栏壁纸
博主头像
PySuper博主等级

千里之行,始于足下

  • 累计撰写 203 篇文章
  • 累计创建 14 个标签
  • 累计收到 1 条评论

目 录CONTENT

文章目录
Web

Django 上传 / 下载 大文件

PySuper
2020-06-04 / 0 评论 / 0 点赞 / 19 阅读 / 6192 字
温馨提示:
所有牛逼的人都有一段苦逼的岁月。 但是你只要像SB一样去坚持,终将牛逼!!! ✊✊✊

lock = threading.Lock() # 创建一个锁的实例

上传

  • Q:只有获取到用户所有信息之后才能进行上传操作
  • Rollback:文件保存云盘,文件信息(Tag)保存MySQL
  • Lock:鉴于操作文件时多个请求访问同一变量,对用户的数据进行加锁
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
0
  1. 支付宝打赏

    qrcode alipay
  2. 微信打赏

    qrcode weixin

评论区