• 企业400电话
  • 网络优化推广
  • AI电话机器人
  • 呼叫中心
  • 全 部 栏 目

    网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    django上传文件的三种方式
    POST TIME:2021-10-18 14:07

    Django文件上传需要考虑的重要事项

    文件或图片一般通过表单进行。用户在前端点击文件上传,然后以POST方式将数据和文件提交到服务器。服务器在接收到POST请求后需要将其存储在服务器上的某个地方。Django默认的存储地址是相对于根目录的/media/文件夹,存储的默认文件名就是文件本来的名字。上传的文件如果不大于2.5MB,会先存入服务器内存中,然后再写入磁盘。如果上传的文件很大,Django会把文件先存入临时文件,再写入磁盘。

    Django默认处理方式会出现一个问题,所有文件都存储在一个文件夹里。不同用户上传的有相同名字的文件可能会相互覆盖。另外用户还可能上传一些不安全的文件如js和exe文件,我们必需对允许上传文件的类型进行限制。因此我们在利用Django处理文件上传时必需考虑如下3个因素:

    注意:以上事项对于上传图片是同样适用的。

    Django文件上传的3种常见方式

    Django文件上传一般有3种方式(如下所示)。我们会针对3种方式分别提供代码示范。

    Ajax文件上传部分见Django与Ajax交互篇。

    项目创建与设置

    我们先使用django-admin startproject命令创建一个叫file_project的项目,然后cd进入file_project, 使用python manage.py startapp创建一个叫file_upload的app。

    我们首先需要将file_upload这个app加入到我们项目里,然后设置/media/和/STATIC_URL/文件夹。我们上传的文件都会放在/media/文件夹里。我们还需要使用css和js这些静态文件,所以需要设置STATIC_URL。

    #file_project/settings.py
    
    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'file_upload',# 新增
    ]
    
    STATIC_URL = '/static/'
    STATICFILES_DIRS = [os.path.join(BASE_DIR, "static"), ]
    
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    MEDIA_URL = '/media/'
    
    #file_project/urls.py
    from django.contrib import admin
    from django.urls import path, include
    from django.conf import settings
    from django.conf.urls.static import static
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('file/', include("file_upload.urls")),
    ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

    创建模型

    使用Django上传文件创建模型不是必需,然而如果我们需要对上传文件进行系统化管理,模型还是很重要的。我们的File模型包括file和upload_method两个字段。我们通过upload_to选项指定了文件上传后存储的地址,并对上传的文件名进行了重命名。

    #file_upload/models.py
    from django.db import models
    import os
    import uuid
    
    # Create your models here.
    # Define user directory path
    def user_directory_path(instance, filename):
        ext = filename.split('.')[-1]
        filename = '{}.{}'.format(uuid.uuid4().hex[:10], ext)
        return os.path.join("files", filename)
    
    class File(models.Model):
        file = models.FileField(upload_to=user_directory_path, null=True)
        upload_method = models.CharField(max_length=20, verbose_name="Upload Method")

    注意:如果你不使用ModelForm,你还需要手动编写代码存储上传文件。

    URLConf配置

    本项目一共包括3个urls, 分别对应普通表单上传,ModelForm上传和显示文件清单。

    #file_upload/urls.py
    from django.urls import re_path, path
    from . import views
    
    # namespace
    app_name = "file_upload"
    
    urlpatterns = [
        # Upload File Without Using Model Form
        re_path(r'^upload1/$', views.file_upload, name='file_upload'),
    
        # Upload Files Using Model Form
        re_path(r'^upload2/$', views.model_form_upload, name='model_form_upload'),
    
        # View File List
        path('file/', views.file_list, name='file_list'),
    
    ]

    使用一般表单上传文件

    我们先定义一个一般表单FileUploadForm,并通过clean方法对用户上传的文件进行验证,如果上传的文件名不以jpg, pdf或xlsx结尾,将显示表单验证错误信息。关于表单的自定义和验证更多内容见Django基础: 表单forms的设计与使用。

    #file_upload/forms.py
    
    from django import forms
    from .models import File
    
    # Regular form
    class FileUploadForm(forms.Form):
        file = forms.FileField(widget=forms.ClearableFileInput(attrs={'class': 'form-control'}))
        upload_method = forms.CharField(label="Upload Method", max_length=20,
                                       widget=forms.TextInput(attrs={'class': 'form-control'}))
        def clean_file(self):
            file = self.cleaned_data['file']
            ext = file.name.split('.')[-1].lower()
            if ext not in ["jpg", "pdf", "xlsx"]:
                raise forms.ValidationError("Only jpg, pdf and xlsx files are allowed.")
            # return cleaned data is very important.
            return file

    注意: 使用clean方法对表单字段进行验证时,别忘了return验证过的数据,即cleaned_data。只有返回了cleaned_data, 视图中才可以使用form.cleaned_data.get(‘xxx')获取验证过的数据。

    对应一般文件上传的视图file_upload方法如下所示。当用户的请求方法为POST时,我们通过form.cleaned_data.get('file')获取通过验证的文件,并调用自定义的handle_uploaded_file方法来对文件进行重命名,写入文件。如果用户的请求方法不为POST,则渲染一个空的FileUploadForm在upload_form.html里。我们还定义了一个file_list方法来显示文件清单。

    #file_upload/views.py
    
    from django.shortcuts import render, redirect
    from .models import File
    from .forms import FileUploadForm, FileUploadModelForm
    import os
    import uuid
    from django.http import JsonResponse
    from django.template.defaultfilters import filesizeformat
    
    # Create your views here.
    
    
    # Show file list
    def file_list(request):
        files = File.objects.all().order_by("-id")
        return render(request, 'file_upload/file_list.html', {'files': files})
    
    # Regular file upload without using ModelForm
    def file_upload(request):
        if request.method == "POST":
            form = FileUploadForm(request.POST, request.FILES)
            if form.is_valid():
                # get cleaned data
                upload_method = form.cleaned_data.get("upload_method")
                raw_file = form.cleaned_data.get("file")
                new_file = File()
                new_file.file = handle_uploaded_file(raw_file)
                new_file.upload_method = upload_method
                new_file.save()
                return redirect("/file/")
        else:
            form = FileUploadForm()
    
        return render(request, 'file_upload/upload_form.html', 
                      {'form': form, 'heading': 'Upload files with Regular Form'}
                     )
    
    def handle_uploaded_file(file):
        ext = file.name.split('.')[-1]
        file_name = '{}.{}'.format(uuid.uuid4().hex[:10], ext)
    
        # file path relative to 'media' folder
        file_path = os.path.join('files', file_name)
        absolute_file_path = os.path.join('media', 'files', file_name)
    
        directory = os.path.dirname(absolute_file_path)
        if not os.path.exists(directory):
            os.makedirs(directory)
    
        with open(absolute_file_path, 'wb+') as destination:
            for chunk in file.chunks():
                destination.write(chunk)
    
        return file_path

    注意:

    上传表单模板upload_form.html代码如下:

    #file_upload/templates/upload_form.html
    {% extends "file_upload/base.html" %}
    {% block content %}
    {% if heading %}
    h3>{{ heading }}/h3>
    {% endif %}
    
    form action="" method="post" enctype="multipart/form-data" >
      {% csrf_token %}
      {{ form.as_p }}
     button class="btn btn-info form-control " type="submit" value="submit">Upload/button>
    /form>
    {% endblock %} 

    显示文件清单模板file_list.html代码如下所示:

    # file_upload/templates/file_list.html
    {% extends "file_upload/base.html" %}
    
    {% block content %}
    h3>File List/h3>
    p> a href="/file/upload1/" rel="external nofollow" >RegularFormUpload/a> | a href="/file/upload2/" rel="external nofollow" >ModelFormUpload/a>
        | a href="/file/upload3/" rel="external nofollow" >AjaxUpload/a>/p>
    {% if files %}
    table class="table table-striped">
        tbody>
        tr>
            td>Filename  URL/td>
            td>Filesize/td>
            td>Upload Method/td>
        /tr>
        {% for file in files %}
        tr>
            td>a href="{{ file.file.url }}" rel="external nofollow" >{{ file.file.url }}/a>/td>
            td>{{ file.file.size | filesizeformat }}/td>
            td>{{ file.upload_method }}/td>
        /tr>
        {% endfor %}
        /tbody>
    /table>
    
    {% else %}
    
    p>No files uploaded yet. Please click a href="{% url 'file_upload:file_upload' %}" rel="external nofollow" >here/a>
        to upload files./p>
    {% endif %}
    {% endblock %}

    注意: 

    使用ModelForm上传文件

    使用ModelForm上传是小编我推荐的上传方式,前提是你已经在模型中通过upload_to选项自定义了用户上传文件存储地址,并对文件进行了重命名。我们首先要自定义自己的FileUploadModelForm,由File模型重建的。代码如下所示:

    #file_upload/forms.py
    from django import forms
    from .models import File
    
    # Model form
    class FileUploadModelForm(forms.ModelForm):
        class Meta:
            model = File
            fields = ('file', 'upload_method',)
            widgets = {
                'upload_method': forms.TextInput(attrs={'class': 'form-control'}),
                'file': forms.ClearableFileInput(attrs={'class': 'form-control'}),
            }
    
        def clean_file(self):
            file = self.cleaned_data['file']
            ext = file.name.split('.')[-1].lower()
            if ext not in ["jpg", "pdf", "xlsx"]:
                raise forms.ValidationError("Only jpg, pdf and xlsx files are allowed.")
            # return cleaned data is very important.
            return file

    使用ModelForm处理文件上传的视图model_form_upload方法非常简单,只需调用form.save()即可,无需再手动编写代码写入文件。

    #file_upload/views.py
    
    from django.shortcuts import render, redirect
    from .models import File
    from .forms import FileUploadForm, FileUploadModelForm
    import os
    import uuid
    from django.http import JsonResponse
    from django.template.defaultfilters import filesizeformat
    
    # Create your views here.
    # Upload File with ModelForm
    
    def model_form_upload(request):
        if request.method == "POST":
            form = FileUploadModelForm(request.POST, request.FILES)
            if form.is_valid():
                form.save() # 一句话足以
                return redirect("/file/")
        else:
            form = FileUploadModelForm()
    
        return render(request, 'file_upload/upload_form.html', 
                      {'form': form,'heading': 'Upload files with ModelForm'}
                     )

    模板跟前面一样,这里就不展示了。

    GitHub源码地址

    https://github.com/shiyunbo/django-file-upload-download

    小结

    本文提供并解读了利用Django上传文件的3种主要方式(一般表单上传,ModelForm上传和Ajax上传)及示范代码。

    以上就是django上传文件的三种方式的详细内容,更多关于django上传文件的资料请关注脚本之家其它相关文章!

    您可能感兴趣的文章:
    • Django 如何实现文件上传下载
    • Django和Ueditor自定义存储上传文件的文件名
    • 详解Django自定义图片和文件上传路径(upload_to)的2种方式
    • 基于django和dropzone.js实现上传文件
    • python中Django文件上传方法详解
    • Django后端分离 使用element-ui文件上传方式
    • Django Admin 上传文件到七牛云的示例代码
    • Django实现任意文件上传(最简单的方法)
    • Django 解决上传文件时,request.FILES为空的问题
    • Django中文件上传和文件访问微项目的方法
    • django 文件上传功能的相关实例代码(简单易懂)
    上一篇:详解Django的MVT设计模式
    下一篇:Django项目如何正确配置日志(logging)
  • 相关文章
  • 

    关于我们 | 付款方式 | 荣誉资质 | 业务提交 | 代理合作


    © 2016-2020 巨人网络通讯

    时间:9:00-21:00 (节假日不休)

    地址:江苏信息产业基地11号楼四层

    《增值电信业务经营许可证》 苏B2-20120278

    X

    截屏,微信识别二维码

    微信号:veteran88

    (点击微信号复制,添加好友)

     打开微信