Django文件上传和下载

对于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 url
from fileoperation import views

urlpatterns = [
    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 render
from django.views.decorators.http import require_GET, require_POST
from django.http import HttpResponse
from django.core.files import File
import os

SAVED_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_GET
def home(request):
    if not os.path.exists(SAVED_FILES_DIR):
        os.makedirs(SAVED_FILES_DIR)

    return render_home_template(request)

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


download视图函数

@require_GET
def 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_POST
def 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直接可以实现大文件上传,而不必担心占用过多的内存。



  • 0
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值