Django17-文件上传下载

一、文件上传

方法一:简单的文件上传

前端页面获取上传的文件后,后端通过request.FILES.get('file)来接收
打开一个新的文件,将接收的文件写入新文件中,读取文件时要使用file.chunks()方法

 views.py

from devops.settings import BASE_DIR

def file_add(request):
    filepath = os.path.join(BASE_DIR, 'data/scripts/')
    if request.method == 'POST':
        file = request.FILES.get('file')
        filename = file.name
        with open(filepath+filename,'wb') as f:
            for line in file.chunks():
                f.write(line)
            return redirect(reverse('file_list'))
    return render(request, 'file_add.html')

urls.py

from django.urls import path
from mfile import views

urlpatterns=[
    path('list/',views.filelist,name='file_list'),
       path('add/',views.file_add,name='file_add'),
]

templates/file_list.html

{% extends 'base.html' %}

{% block body%}
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
    {% csrf_token %}
    <div>
        <input type="file" name="file">
    </div>
    <button class="btn btn-primary">提交</button>
</form>

{% endblock %}

方法二:

通过ModelForm实现,将文件路径保存在数据库中

settings.py

# 配置文件保存的目录信息
FILE_ROOT = os.path.join(BASE_DIR,'data/scripts/')

urls.py

from django.urls import path
from mfile import views

urlpatterns = [
    path('filelist/', views.FileList.as_view(), name='file_list'),
    path('fileadd/', views.FileAdd.as_view(), name='file_add'),
]

models.py

from django.db import models
from devops import settings

class File(models.Model):
    title = models.TextField(max_length=32)
    file = models.FileField(upload_to=settings.FILE_ROOT)

forms.py

from django import forms
from mfile import models

class FileForm(forms.ModelForm):
    class Meta:
        model = models.File
        fields = '__all__'

views.py

from django.views import View
from mfile import models, forms

class FileList(View):
    def get(self, request):
        files = models.File.objects.all()
        return render(request, 'file_list.html', {'files': files})


class FileAdd(View):
    def get(self,request):
        form_obj = forms.FileForm()
        return render(request,'file_add.html',{'form_obj':form_obj})

    def post(self,request):
        form_obj = forms.FileForm(request.POST,request.FILES)
        if form_obj.is_valid():
            form_obj.save()
        return redirect(reverse('file_list'))

templates/file_list.html

{% extends 'base.html' %}

{% block body %}
<table class="table">
    <tr>
        <td>序号</td>
        <td>标题</td>
        <td>文件路径</td>
    </tr>
    {% for file in files %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ file.title }}</td>
            <td>{{ file.file}}</td>
        </tr>
    {% endfor %}
</table>
    <div class="form-group">
        <button>
            <a href="{% url 'file_add' %}" >文件上传</a>
        </button>
    </div>

{% endblock %}

templates/file_add.html

{% extends 'base.html' %}

{% block body%}
<form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
    {% csrf_token %}
    <div>
        <span>标题</span>
        <input type="text" name="title">
    </div>
    <div>
        <input type="file" name="file">
    </div>
    <button class="btn btn-primary">提交</button>
</form>

{% endblock %}

在数据库表中保存了文件信息和保存的路径

在访问filelist时可显示文件信息

二、文件下载

前端页面提供一个下载文件的id,views通过文件id从数据库中查出文件保存路径,将文件返回给用户即可。

urls.py

from django.urls import path
from mfile import views

urlpatterns = [
    path('filelist/', views.FileList.as_view(), name='file_list'),
    path('fileupload/', views.FileUpload.as_view(), name='file_upload'),
    path('filedownload/<int:id>/', views.FileDownload.as_view(), name='file_download'),

]

views.py

from django.views import View
from devops.settings import FILE_ROOT
from mfile import models, forms

class FileDownload(View):
    def get(self,request,id):
        file_obj = models.File.objects.get(id=id).file
              # 获取文件名称
        filename = str(file_obj).split('/')[-1]
        filepath = os.path.join(FILE_ROOT,filename)

      #这里不能用with open打开文件
        file = open(filepath,'rb')
        rep = FileResponse(file)
        rep['Content-Type'] = 'application/octet-stream'
        rep['Content-Disposition'] = 'attachment;filename="%s"'%filename
        return rep

templates/filelist.html

{% extends 'base.html' %}

{% block body %}
<table class="table">
    <tr>
        <td>序号</td>
        <td>标题</td>
        <td>文件路径</td>
    </tr>
    {% for file in files %}
        <tr>
            <td>{{ forloop.counter }}</td>
            <td>{{ file.title }}</td>
            <td>{{ file.file}}</td>
            <td><a href="{% url 'file_download' file.id %}"><button class="btn btn-primary">下载</button></a></td> #给后端传一个id值
        </tr>
    {% endfor %}
</table>
    <div class="form-group">
        <button>
            <a href="{% url 'file_upload'%}" >文件上传</a>
        </button>
    </div>

{% endblock %}

返回文件有三种方式:

方式一:使用HttpResponse

from django.shortcuts import HttpResponse

class FileDownload(View):
    def get(self,request,id):
        file_obj = models.File.objects.get(id=id).file
              # 获取文件名称
        filename = str(file_obj).split('/')[-1]
        filepath = os.path.join(FILE_ROOT,filename)

      #这里不能用with open打开文件
        file = open(filepath,'rb')
        rep = HttpResponse(file)
        rep['Content-Type'] = 'application/octet-stream'
        rep['Content-Disposition'] = 'attachment;filename="%s"'%filename
        return rep

方式二:使用StreamingHttpResponse

from django.http import StreamingHttpResponse

class FileDownload(View):
    def get(self,request,id):
        file_obj = models.File.objects.get(id=id).file
              # 获取文件名称
        filename = str(file_obj).split('/')[-1]
        filepath = os.path.join(FILE_ROOT,filename)

      #这里不能用with open打开文件
        file = open(filepath,'rb')
        rep = StreamingHttpResponse(file)
        rep['Content-Type'] = 'application/octet-stream'
        rep['Content-Disposition'] = 'attachment;filename="%s"'%filename
        return rep

方式三:使用FileResponse(推荐)

from django.http import FileResponse

class FileDownload(View):
    def get(self,request,id):
        file_obj = models.File.objects.get(id=id).file
              # 获取文件名称
        filename = str(file_obj).split('/')[-1]
        filepath = os.path.join(FILE_ROOT,filename)

      #这里不能用with open打开文件
        file = open(filepath,'rb')
        rep = FileResponse(file)
        rep['Content-Type'] = 'application/octet-stream'
        rep['Content-Disposition'] = 'attachment;filename="%s"'%filename
        return rep

三种http响应对象在django官网都有介绍。https://docs.djangoproject.com/en/1.11/ref/request-response/

推荐使用FileResponse,从源码中可以看出FileResponse是StreamingHttpResponse的子类,内部使用迭代器进行数据流传输。

原文地址:https://www.cnblogs.com/dxnui119/p/14060139.html