django 实现文件下载功能

发布时间:2020-02-13 12:08:28编辑:admin阅读(2980)

    一、概述

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

    前端实现方式

    a标签+响应头信息

    <a href="/download/1/">下载图片</a>

     

    注意:这里的1指的是MySQL表的主键id

     

    后端实现方式

    使用django有三种文件下载方式,分别是HttpResponse,StreamingHttpResponse,FileResponse

    详情,请参考链接

    https://www.jb51.net/article/137790.htm

     

    本文主要介绍StreamingHttpResponse实现方式

     

    二、实际操作

    新建项目

    新建一个Django项目untitled1,这里的是Django 2.x版本。

    目录结构如下:

    ./
    ├── app
    │   ├── admin.py
    │   ├── apps.py
    │   ├── __init__.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── manage.py
    ├── templates
    │   └── index.html
    ├── untitled1
    │   ├── __init__.py
    │   ├── settings.py
    │   ├── urls.py
    │   └── wsgi.py
    └── upload
        └── images
            └── animation.jpg


    默认创建了一个应用,名叫app

    upload是用来存放上传的图片

     

    简单示例

    这里以一个简单的页面,来介绍如何实现下载功能!

     

    修改urls.py,增加路由。

    注意:红色部分,是需要修改的

    from django.contrib import admin
    from django.urls import path,re_path
    from app import views
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('', views.index),
        re_path('download/(?P<id>\d+)', views.file_down,name = "download"),
    ]


    修改views.py,增加视图函数

    from django.shortcuts import render, HttpResponse
    from django.http import StreamingHttpResponse
    import os
    
    def index(request):
        return render(request,"index.html")
    
    # Create your views here.
    def file_down(request, id):
        """
        下载压缩文件
        :param request:
        :param id: 数据库id
        :return:
        """
        data = [{"id":"1","image":"animation.jpg"}]  # 模拟mysql表数据
        file_name = ""  # 文件名
        for i in data:
            if i["id"] == id:  # 判断id一致时
                file_name = i["image"]  # 覆盖变量
        
        base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))  # 项目根目录
        file_path = os.path.join(base_dir, 'upload','images', file_name)  # 下载文件的绝对路径
    
        if not os.path.isfile(file_path):  # 判断下载文件是否存在
            return HttpResponse("Sorry but Not Found the File")
    
        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:
                    c = f.read(chunk_size)
                    if c:
                        yield c
                    else:
                        break
    
        try:
            # 设置响应头
            # StreamingHttpResponse将文件内容进行流式传输,数据量大可以用这个方法
            response = StreamingHttpResponse(file_iterator(file_path))
            # 以流的形式下载文件,这样可以实现任意格式的文件下载
            response['Content-Type'] = 'application/octet-stream'
            # Content-Disposition就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名
            response['Content-Disposition'] = 'attachment;filename="{}"'.format(file_name)
        except:
            return HttpResponse("Sorry but Not Found the File")
    
        return response

     

    代码解释:

    index是默认的首页展示

    file_down 是用来做下载的。

    为了简单实现,在file_down 中的data,表示数据库中的记录。需要指定id才能对应的文件!

    其他代码,有详细的注释,这里就不多介绍了

     

    修改index.html,注意:这里需要指定id。这里仅做示例,固定了id。

    实际情况应该查询数据库,使用Django模板引擎来渲染的

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <a href="/download/1/">下载图片</a>
    </body>
    </html>


    upload目录是用来存放上传文件的。在images里面我放了一张动漫图片!

     

    启动项目,访问首页:

    这里使用的是edge浏览器

    1.png

     

    点击下载图片,浏览器底部会有提示

    点击打开

     

    就会打开图片,效果如下:

     3.png


关键字