Django文件上传和下载

来源:互联网 发布:传奇霸业战神装备数据 编辑:程序博客网 时间:2024/06/16 09:04

对于Web应用,经常需要实现文件的上传和下载,今天就来介绍一下使用Django如何实现文件的上传和下载。


先来创建一个Django项目,名称为FileService:

django-admin startproject FileService


创建应用fileoperation

python3 manage.py startapp fileoperation


在项目的FileService/settings.py中的INSTALLED_APPS中添加fileoperation应用

INSTALLED_APPS = [

    ......

    'fileoperation',

]


在项目的fileoperation/目录下创建目录templates目录,用于放置模板,创建模板home.html

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>上传下载</title></head><body>    <form action="{% url 'upload'%}" enctype="multipart/form-data" method="post">        {% csrf_token %}        <input type="file" name="filename" value="">        <input type="submit" value="上传">    </form>    <ul>        {% for file in files %}            <li><a href="{% url 'download' file %}">{{ file }}</a></li>        {% endfor %}    </ul></body></html>

模板很简单,主要是实现了一个enctype为multipart/form-data的form,将表单提交到upload请求,然后页面会显示当前已经上传的文件,点击条目,可以进行文件下载,这样我们就可以通过页面进行上传和下载了。


配置FileService/urls.py文件,这里为了简便,我没有将url配置在fileoperation目录下的urls.py,而是直接使用fileoperation包下的views.py。

from django.conf.urls import urlfrom fileoperation import viewsurlpatterns = [    url(r'^$', views.home, name='home'),    url(r'^upload/$', views.upload, name='upload'),    url(r'^download/(?P<filename>.+)$', views.download, name='download'),]

前两个配置,如果看过之前的文章应该很好理解,这里重点看一下download请求的正则表达式,其后使用

(?P<filename>.+)


构建了一个带有路径参数的url,用来表示该url后会跟一个文件名,例如,如果我文件名为a.txt,则url会是

download/a.txt


其中a.txt会作为filename参数,赋值给我们views.download函数的filename参数,稍后就会看到。


下面看一下fileoperation/views.py的内容,首先是import部分,其中还定义了一个全局变量,表示保存文件的路径,require_GET和require_POST是两个修饰符,用来规定对应的视图函数只能执行GET或POST请求

from django.shortcuts import renderfrom django.views.decorators.http import require_GET, require_POSTfrom django.http import HttpResponsefrom django.core.files import Fileimport osSAVED_FILES_DIR = r'files/'

下面是一个函数,用来渲染home.html模板

def render_home_template(request):    files = os.listdir(SAVED_FILES_DIR)    return render(request, 'home.html', {'files': files})

home请求的视图函数

@require_GETdef home(request):    if not os.path.exists(SAVED_FILES_DIR):        os.makedirs(SAVED_FILES_DIR)    return render_home_template(request)

比较简单,判断是否存在保存文件的目录,如果不存在,创建该目录,然后渲染home.html模板。


download视图函数

@require_GETdef download(request, filename):    file_pathname = os.path.join(SAVED_FILES_DIR, filename)    with open(file_pathname, 'rb') as f:        file = File(f)        response = HttpResponse(file.chunks(),                                content_type='APPLICATION/OCTET-STREAM')        response['Content-Disposition'] = 'attachment; filename=' + filename        response['Content-Length'] = os.path.getsize(file_pathname)    return response

下载流程很简单,打开需要下载的文件,filename参数就是前面url配置的路径参数,将Python的文件对象使用Django的文件对象进行包裹,然后创建HttpResponse对象,给该对象传入chunks()返回的生成器,该生成器每次生成最多64kb的文件数据,然后传输给客户端。


上传视图函数

@require_POSTdef upload(request):    file = request.FILES.get("filename", None)    if not file:        return render_home_template(request)    pathname = os.path.join(SAVED_FILES_DIR, file.name)    with open(pathname, 'wb+') as destination:        for chunk in file.chunks():            destination.write(chunk)    return render_home_template(request)

上传的逻辑也不复杂,从request的FILES中取到filename对应的django file对象,然后创建输出文件,将django file对象的chunks写入输出文件。


可以看到,Django实现上传和下载非常简单,代码也比较简洁,而且,使用chunks直接可以实现大文件上传,而不必担心占用过多的内存。