• vue+django实现下载文件


    一、概述

    在项目中,点击下载按钮,就可以下载文件。

    传统的下载链接一般是get方式,这种链接是公开的,可以任意下载。

    在实际项目,某些下载链接,是私密的。必须使用post方式,传递正确的参数,才能下载。

    二、django项目

    本环境使用django 3.1.5,新建项目download_demo

    安装模块

    pip3 install djangorestframework django-cors-headers

     修改文件download_demo/settings.py

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'api.apps.ApiConfig',
        'corsheaders',  # 注册应用cors
    ]

    注册中间件

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'corsheaders.middleware.CorsMiddleware',  # 注册组件cors
    ]

    最后一行增加

    # 跨域增加忽略
    CORS_ALLOW_CREDENTIALS = True
    CORS_ORIGIN_ALLOW_ALL = True
    
    CORS_ALLOW_METHODS = (
        'GET',
        'OPTIONS',
        'PATCH',
        'POST',
        'VIEW',
    )
    
    CORS_ALLOW_HEADERS = (
        'XMLHttpRequest',
        'X_FILENAME',
        'accept-encoding',
        'authorization',
        'content-type',
        'dnt',
        'origin',
        'user-agent',
        'x-csrftoken',
        'x-requested-with',
        'Pragma',
    )

    修改download_demo/urls.py

    from django.contrib import admin
    from django.urls import path
    from api import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('download/excel/', views.ExcelFileDownload.as_view()),
    ]

    修改api/views.py

    from django.shortcuts import render,HttpResponse
    from download_demo import settings
    from django.utils.encoding import escape_uri_path
    from django.http import StreamingHttpResponse
    from django.http import JsonResponse
    from rest_framework.views import APIView
    from rest_framework import status
    import os
    
    class ExcelFileDownload(APIView):
        def post(self,request):
            print(request.data)
            # filename = "大江大河.xlsx"
            filename = request.data.get("filename")
            download_file_path = os.path.join(settings.BASE_DIR, "upload",filename)
            print("download_file_path",download_file_path)
    
            response = self.big_file_download(download_file_path, filename)
            if response:
                return response
    
            return JsonResponse({'status': 'HttpResponse', 'msg': 'Excel下载失败'})
    
        def file_iterator(self,file_path, chunk_size=512):
            """
            文件生成器,防止文件过大,导致内存溢出
            :param file_path: 文件绝对路径
            :param chunk_size: 块大小
            :return: 生成器
            """
            with open(file_path, mode='rb') as f:
                while True:
                    c = f.read(chunk_size)
                    if c:
                        yield c
                    else:
                        break
    
        def big_file_download(self,download_file_path, filename):
            try:
                response = StreamingHttpResponse(self.file_iterator(download_file_path))
                # 增加headers
                response['Content-Type'] = 'application/octet-stream'
                response['Access-Control-Expose-Headers'] = "Content-Disposition, Content-Type"
                response['Content-Disposition'] = "attachment; filename={}".format(escape_uri_path(filename))
                return response
            except Exception:
                return JsonResponse({'status': status.HTTP_400_BAD_REQUEST, 'msg': 'Excel下载失败'},
                                    status=status.HTTP_400_BAD_REQUEST)
    View Code

    在项目根目录创建upload文件

     里面放一个excel文件,比如:大江大河.xlsx

    三、vue项目

    新建一个vue项目,安装ElementUI 模块即可。

    新建test.vue

    <template>
      <div style=" 70%;margin-left: 30px;margin-top: 30px;">
        <el-button class="filter-item" type="success" icon="el-icon-download" @click="downFile()">下载</el-button>
      </div>
    </template>
    
    <script>
      import axios from 'axios'
    
      export default {
        data() {
          return {
          }
        },
        mounted: function() {
    
        },
        methods: {
          downloadFile(url, options = {}){
            return new Promise((resolve, reject) => {
              // console.log(`${url} 请求数据,参数=>`, JSON.stringify(options))
              // axios.defaults.headers['content-type'] = 'application/json;charset=UTF-8'
              axios({
                method: 'post',
                url: url, // 请求地址
                data: options, // 参数
                responseType: 'blob' // 表明返回服务器返回的数据类型
              }).then(
                response => {
                  // console.log("下载响应",response)
                  resolve(response.data)
                  let blob = new Blob([response.data], {
                    type: 'application/vnd.ms-excel'
                  })
                  // console.log(blob)
                  // let fileName = Date.parse(new Date()) + '.xlsx'
                  // 切割出文件名
                  let fileNameEncode = response.headers['content-disposition'].split("filename=")[1];
                  // 解码
                  let fileName = decodeURIComponent(fileNameEncode)
                  // console.log("fileName",fileName)
                  if (window.navigator.msSaveOrOpenBlob) {
                    // console.log(2)
                    navigator.msSaveBlob(blob, fileName)
                  } else {
                    // console.log(3)
                    var link = document.createElement('a')
                    link.href = window.URL.createObjectURL(blob)
                    link.download = fileName
                    link.click()
                    //释放内存
                    window.URL.revokeObjectURL(link.href)
                  }
                },
                err => {
                  reject(err)
                }
              )
            })
          },
          // 下载文件
          downFile(){
            let postUrl= "http://127.0.0.1:8000/download/excel/"
            let params = {
              filename: "大江大河.xlsx",
            }
            // console.log("下载参数",params)
            this.downloadFile(postUrl,params)
          },
        }
      }
    </script>
    
    <style>
    </style>
    View Code

    注意:这里使用post请求,并将filename传输给api,用来下载指定的文件。 

    访问测试页面,点击下载按钮

     就会自动下载

    打开工具栏,查看响应信息

    这里,就是django返回的文件名,浏览器下载保存的文件名,也是这个。

    遇到中文,会进行URLcode编码。

    所以在vue代码中,对Content-Disposition做了切割,得到了文件名。

  • 相关阅读:
    vs2008 当前上下文不存在名称xxx 解决办法
    SQL Server 2008故障转移集群+数据库镜像配置实例之一
    通过JavaScript获取页面大小
    使用JavaScript判断浏览器类型
    sql2008安装图解sql2008安装全过程
    Sqlserver中对时间类型的字段转换
    SQL Server 2008故障转移集群+数据库镜像配置实例之三
    这年头口罩都成时尚品
    一位软件工程师的6年总结[转]
    MS SQL Server查询优化方法[转]
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/14361942.html
Copyright © 2020-2023  润新知