• 技术文章 >Python框架 >Django

    django如何从服务端下载文件到本地

    silencementsilencement2019-08-19 09:12:55原创6017

    在实际的项目中很多时候需要用到下载功能,如导excel、pdf或者文件下载,当然你可以使用web服务自己搭建可以用于下载的资源服务器,如nginx,这里我们主要介绍django中的文件下载。

    这里我们将下载的文件存放在项目media目录下,当然在实际中并不会这样做。

    方式一:使用HttpResponse

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    import os

    from django.http import HttpResponse, Http404

    def media_file_download(request, file_path):

       with open(file_path, 'rb') as f:

           try:

               response = HttpResponse(f)

               response['content_type'] = "application/octet-stream"

               response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)

               return response

           except Exception:

               raise Http404

    HttpResponse有个很大的弊端,其工作原理是先读取文件,载入内存,然后再输出。如果下载文件很大,该方法会占用很多内存。对于下载大文件,Django更推荐StreamingHttpResponse和FileResponse方法,这两个方法将下载文件分批(Chunks)写入用户本地磁盘,先不将它们载入服务器内存。

    方式二:使用StreamingHttpResponse

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    import os

    from django.http import HttpResponse, Http404, StreamingHttpResponse

    def stream_http_download(request, file_path):

       try:

           response = StreamingHttpResponse(open(file_path, 'rb'))

           response['content_type'] = "application/octet-stream"

           response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)

           return response

       except Exception:

           raise Http404

    方式三:使用FileResponse

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    import os

    from django.http import HttpResponse, Http404, FileResponse

    def file_response_download1(request, file_path):

       try:

           response = FileResponse(open(file_path, 'rb'))

           response['content_type'] = "application/octet-stream"

           response['Content-Disposition'] = 'attachment; filename=' + os.path.basename(file_path)

           return response

       except Exception:

           raise Http404

    文件名中文乱码问题

    其中用英文的文件名,浏览器显示正常,但是用了中文后,就是默认的文件名,如下载.xls,或者如果我用了utf-8编码,是乱码。解决方法如下:

    1

    response['Content-Disposition'] = "attachment; filename*=utf-8''{}".format(escape_uri_path(name))

    文件私有化的两种方法

    如果你想实现只有登录过的用户才能查看和下载某些文件,大概有两种方法,这里仅提供思路。

    上传文件放在media文件夹,文件名使用很长的随机字符串命名(uuid), 让用户无法根据文件名猜出这是什么文件。视图和模板里验证用户是否已登录,登录或通过权限验证后才显示具体的url。- 简单易实现,安全性不高,但对于一般项目已足够。

    上传文件放在非media文件夹,用户即使知道了具体文件地址也无法访问,因为Django只会给media文件夹里每个文件创建独立url资源。视图和模板里验证用户是否已登录,登录或通过权限验证后通过自己编写的下载方法下载文件。- 安全性高,但实现相对复杂。

    个人下载文档view视图代码

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    from django.views import View

    from django.conf import settings

    from django.http import FileResponse,Http404

    from django.utils.encoding import escape_uri_path

    from .models import Doc

    import requests

    import logging

    logger = logging.getLogger('django')

    class Download(View):

        """

        前端传来下载doc的id,后端传给它下载地址

        """

        def get(self,request,doc_id):

            doc = Doc.objects.only('file_url').filter(is_delete=False,id = doc_id).first()

            if doc:

                doc_url = doc.file_url

                doc_url = settings.ITEM_DOMAIN_PORT + doc_url

                try:

                    res = FileResponse(requests.get(doc_url,stream = True))

                except Exception as e:

                    logger.info('文件获取异常:{}'.format(e))

                    raise Http404('文件获取异常')

                file_end = doc_url.split('.')[-1]

                if not file_end:

                    raise Http404('文档路径出错')

                else:

                    file_end = file_end.lower()

                if file_end == "pdf":

                    res["Content-type"] = "application/pdf"

                elif file_end == "zip":

                    res["Content-type"] = "application/zip"

                elif file_end == "doc":

                    res["Content-type"] = "application/msword"

                elif file_end == "xls":

                    res["Content-type"] = "application/vnd.ms-excel"

                elif file_end == "docx":

                    res["Content-type"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"

                elif file_end == "ppt":

                    res["Content-type"] = "application/vnd.ms-powerpoint"

                elif file_end == "pptx":

                    res["Content-type"] = "application/vnd.openxmlformats-officedocument.presentationml.

                    presentation"

                else:

                    raise Http404("文档格式不正确!")

                doc_filename = escape_uri_path(doc_url.split('/')[-1])

                # http1.1 中的规范

                # 设置为inline,会直接打开

                # attachment 浏览器会开始下载

                res["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(doc_filename)

                return res

            else:

                raise Http404("文档不存在!")

    专题推荐:django
    上一篇:django如何获取单数据 下一篇:如何在Django中使用图片

    相关文章推荐

    • django和flask哪个更容易入门

    全部评论我要评论

    © 2021 Python学习网 苏ICP备2021003149号-1

  • 取消发布评论
  • 

    Python学习网