Django高级(七):多文件上传

uploadMulti一次上传多个文件/图片

0.写在前面:

In this tutorial I will guide you through the steps to implement an AJAX multiple file upload with Django using jQuery. For this tutorial we will be using a specific plug-in called jQuery File Upload, which takes care of the server communication using AJAX and also the compatibility with different browsers.

Now you will see that the jQuery File Upload comes with several script files, they all have a purpose and you will only need some of them for certain features.

基本settings.py配置

# /root/suyn_website/uploadFiles/uploadFiles/settings.py
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 
#/root/suyn_website/uploadFiles

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'UploadMulti', #
]
注:基本配置和上篇‘uploadOne一次上传一个文件’类似

应用UploadMulti,文件夹树:

root@ubuntu:~/suyn_website/uploadFiles# tree
.
├── LICENSE
├── manage.py
├── media
│   └── photos
├── README.md
├── static
│   ├── css
│   │   ├── bootstrap.min.css
│   │   └── bootstrap.min.css.map
│   ├── fonts
│   │   ├── glyphicons-halflings-regular.eot
│   │   ├── glyphicons-halflings-regular.svg
│   │   ├── glyphicons-halflings-regular.ttf
│   │   ├── glyphicons-halflings-regular.woff
│   │   └── glyphicons-halflings-regular.woff2
│   └── js
│       ├── bootstrap.min.js
│       ├── jquery-3.2.0.min.js
│       └── jquery-file-upload
│           ├── jquery.fileupload.js
│           ├── jquery.iframe-transport.js
│           └── vendor
│               └── jquery.ui.widget.js
├── staticRoot
├── templates
│   ├── base.html
│   ├── home.html
│   └── includes
│       └── header.html
├── uploadFiles
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   ├── wsgi.py
└── UploadMulti
    ├── admin.py
    ├── apps.py
    ├── forms.py
    ├── __init__.py
    ├── migrations
    │   ├── 0001_initial.py
    │   ├── 0001_initial.pyc
    │   ├── __init__.py
    │   └── __init__.pyc
    ├── models.py
    ├── static
    │   └── UploadMulti
    │       └── js
    │           ├── basic-upload.js
    │           ├── drag-and-drop-upload.js
    │           └── progress-bar-upload.js
    ├── templates
    │   └── UploadMulti
    │       ├── base.html
    │       ├── basic_upload
    │       │   └── index.html
    │       ├── drag_and_drop_upload
    │       │   └── index.html
    │       └── progress_bar_upload
    │           └── index.html
    ├── tests.py
    ├── urls.py
    └── views.py

1.home主页只是简单的介绍

主页模板继承:
uploadFiles/templates/home.html继承自uploadFiles/templates/base.html的'block content'

Django高级(七):多文件上传_第1张图片
127.0.0.0:8000
##### uploadFiles/uploadFiles/urls.py 
from django.conf.urls import url,include
from django.contrib import admin
from django.conf.urls.static import static
from uploadFiles import settings
from django.views.generic import TemplateView

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    #url(r'^UploadOne/',include('UploadOne.urls')),
    url(r'^$', TemplateView.as_view(template_name='home.html'), name='home'),  #这部分重点看home.html主页
    url(r'^UploadMulti/',include('UploadMulti.urls',namespace='UploadMulti')),
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


##### uploadFiles/templates/home.html
{% extends 'base.html' %}  ##

{% block content %}
    

Multiple File Upload Example

See the example live clicking in the Photos menu.


Static Assets

Following the list of static assets used in this example

{% endblock %} ##### uploadFiles/templates/base.html {% load static %} {% block title %}Photos Library - Simple is Better Than Complex{% endblock %} {% include 'includes/header.html' %} ##
{% block content %} {% endblock %}
{### Bootstrap and jQuery in the base template, ## and the jQuery File Upload plug-in will be added using the {% block javascript %} #} ##引入支持的Jquery脚本 ##引入支持的bootstrap脚本 {% block javascript %} {% endblock %} ##### uploadFiles/templates/includes/header.html

2.Photos涉及有三个链接,针对三种多文件上传方式。

  • Basic Upload
  • Progress Bar Upload
  • Drag and Drop Upload

三种方式模板继承:

各自的uploadFiles/UploadMulti/templates/UploadMulti/basic_upload/index.html继承自uploadFiles/UploadMulti/templates/UploadMulti/base.html'block photocontent''bock title'('Photos/xxx'指定三种方式)。

上面的base.html的'Example'包含三种方式的链接请求,分别指向三种视图函数,该base.html再继承自uploadFiles/templates/base.html(包含includes/header.html)。

关键的一点是,三种方式的Index.html文件都包含与服务器通信的js脚本文件,是继承自uploadFiles/templates/base.html的'block javascript'

一些公共代码及模型表单创建:

##### uploadFiles/UploadMulti/urls.py
# 关于'Class-Based Views vs. Function-Based Views'可参看其他文章
from django.conf.urls import url

from . import views

app_name = 'UploadMulti'

urlpatterns = [
    url(r'^clear/$', views.clear_database, name='clear_database'),
    url(r'^basic-upload/$', views.BasicUploadView.as_view(), name='basic_upload'),
    url(r'^progress-bar-upload/$', views.ProgressBarUploadView.as_view(), name='progress_bar_upload'),
    url(r'^drag-and-drop-upload/$', views.DragAndDropUploadView.as_view(), name='drag_and_drop_upload'),
]

##### uploadFiles/UploadMulti/models.py
class Photo(models.Model):
    title = models.CharField(max_length=255, blank=True)
    file = models.FileField(upload_to='photos/')  ##FileField 文件图片都可以上传
    uploaded_at = models.DateTimeField(auto_now_add=True)

##### uploadFiles/UploadMulti/forms.py
from django import forms
from .models import Photo

class PhotoForm(forms.ModelForm):
    class Meta:
        model = Photo
        fields = ('file', )

2.0. 写在前面:关于'clear_database'

##### views.py
def clear_database(request):
    for photo in Photo.objects.all():
        photo.file.delete()
        photo.delete()
    return redirect(request.POST.get('next'))


##### UploadMulti/base.html
{% extends 'base.html' %}

{% block content %}
{# #### 这里的表单实现对上传文件/图片的清空,同时清空本地 #}
{% csrf_token %}

Photos / {% block title %}{% endblock %} ###

{% block photos_content %} ### {% endblock %}
{% endblock %}

2.1. Basic Upload

Django高级(七):多文件上传_第2张图片
http://127.0.0.1:8000/UploadMulti/basic-upload/

We are using a basic Class-Based View, defining two request processing for the GET and POST methods. For the POST, it is where the upload handling happens, using Django’s Model Forms. When we call form.save(), Django will create a Photo instance and save the file in the file system.

2.1.1.介绍下用到的jquery-file-upload插件功能:

{% block javascript %}  ##from templates/base.html用到了jquery-file-upload插件
    {# JQUERY FILE UPLOAD SCRIPTS #}
    
    
    

    {# PHOTOS PAGE SCRIPTS #}
    
{% endblock %}
  • jquery.ui.widget.js It’s a dependency for the plug-in
  • jquery.iframe-transport.js The Iframe Transport is required for browsers without support for XHR file uploads
  • jquery.fileupload.js The basic File Upload plug-in
    And finally the script basic-upload.js is where we will implement our photo upload.

2.1.2.介绍下index.html页面上几个代码块:

{% block photos_content %}  ##from UploadMulti/base.html
{# 1. BUTTON TO TRIGGER THE ACTION #} {# 2. FILE INPUT TO BE USED BY THE PLUG-IN #}
{# 3. TABLE TO DISPLAY THE UPLOADED PHOTOS #} {% for photo in photos %} {% endfor %} {% endblock %}
  • block 1 of the snippet, is the button to start the workflow. We will hook into the css class .js-upload-photos to open the file explorer window.
  • Block 2 is the most important part of the page. It’s the the file input that will be used to load the jQuery File Upload component. A few things to note:

The name of the input must match with the *Model Form Field(FileField). 也就是,name属性必须和‘file = models.FileField(upload_to='photos/')’一致。
The multiple attribute will enable multiple file selection in the file explorer window.
The data-url attribute must point to the route/view where the file form will be processed.
The data-form-data attribute should be defined exactly this way! This line is important so to instruct the plug-in to send the file along with the csrf middleware token.

  • block 3 is just a regular table displaying the photos.
##### uploadFiles/UploadMulti/views.py
from django.shortcuts import render,redirect
from django.http import JsonResponse
from django.views import View
import time
from .forms import PhotoForm
from .models import Photo
# Create your views here.

class BasicUploadView(View):
    def get(self, request):
        photos_list = Photo.objects.all()
        return render(self.request, 'UploadMulti/basic_upload/index.html', {'photos': photos_list})  ##渲染index.html,传递文件/图像对象

    def post(self, request):
        form = PhotoForm(self.request.POST, self.request.FILES)
        if form.is_valid():
            photo = form.save()   ##保存到本地
            data = {'is_valid': True, 'name': photo.file.name, 'url': photo.file.url}
        else:
            data = {'is_valid': False}
        return JsonResponse(data)  ###JSON格式的data,传递给js



##### uploadFiles/UploadMulti/templates/UploadMulti/basic_upload/index.html
{% extends 'UploadMulti/base.html' %}  ##

{% load static %}

{% block title %}Basic Upload{% endblock %}  ##from UploadMulti/base.html

##(公共代码:各自选择自己的upload js实现)
{% block javascript %}  ##from templates/base.html用到了jquery-file-upload插件
    {# JQUERY FILE UPLOAD SCRIPTS #}
    
    
    

    {# PHOTOS PAGE SCRIPTS #}
    
{% endblock %}

{% block photos_content %}  ##from UploadMulti/base.html
{#### id="fileupload"会在js函数中进一步处理,FILE INPUT TO BE USED BY THE PLUG-IN #}
## 罗列出已经上传的文件/图片(公共代码) {% for photo in photos %} {% endfor %} {% endblock %} ##### uploadFiles/UploadMulti/static/UploadMulti/js/basic-upload.js $(function () { /* 1. OPEN THE FILE EXPLORER WINDOW */ $(".js-upload-photos").click(function () { $("#fileupload").click(); }); /* 2. INITIALIZE THE FILE UPLOAD COMPONENT */ $("#fileupload").fileupload({ ####fileupload dataType: 'json', done: function (e, data) { /* 3. PROCESS THE RESPONSE FROM THE SERVER 这里的data来自于JsonResponse传来的data*/ if (data.result.is_valid) { $("#gallery tbody").prepend( "" + data.result.name + "" ) } } }); });

2.1.3. 介绍data在post方法和js脚本函数中的传递:

    def post(self, request):
        form = PhotoForm(self.request.POST, self.request.FILES)
        if form.is_valid():
            photo = form.save()   ##保存到本地
            data = {'is_valid': True, 'name': photo.file.name, 'url': photo.file.url}
        else:
            data = {'is_valid': False}
        return JsonResponse(data)  ###JSON格式的data,传递给js

  /* 2. INITIALIZE THE FILE UPLOAD COMPONENT */
    $("#fileupload").fileupload({  ####fileupload
        dataType: 'json',
        done: function (e, data) {  /* 3. PROCESS THE RESPONSE FROM THE SERVER  这里的data来自于JsonResponse传来的data*/
              if (data.result.is_valid) {
                  $("#gallery tbody").prepend(
                      "" + data.result.name + ""
                  )
            }
        }
    });
});

This JsonResponse(post method) will end up in the data parameter,
passed to the anonymous function hooked to the done event of the File Upload component.

See what we are doing here? When we are accessing data.result.name, we are accessing the name we returned in the JsonResponse.
So, let’s say, if we returned:
return JsonResponse({'message': 'Success'})

We would be able to catch it inside the done function, this way:

done: function (e, data) {
  if (data.result.message === 'Success') {
    // do something...
  }
}

2.2. Progress Bar Upload

Django高级(七):多文件上传_第3张图片
http://127.0.0.1:8000/UploadMulti/progress-bar-upload/
##### views.py
一样



##### index.html
{# ####这里是页面差别,显示上传的进度条,It’s a Bootstrap modal #}

{% endblock %}

##### progress-bar-upload.js
$(function () {
    $(".js-upload-photos").click(function () {
        $("#fileupload").click();
    });

    $("#fileupload").fileupload({
        dataType: 'json',
        sequentialUploads: true,  /* 1. SEND THE FILES ONE BY ONE 这个属性指示该组件一次发送一个文件*/

        start: function (e) {   /* 2. WHEN THE UPLOADING PROCESS STARTS, SHOW THE MODAL */
            $("#modal-progress").modal("show");
        },

        stop: function (e) {  /* 3. WHEN THE UPLOADING PROCESS FINALIZE, HIDE THE MODAL */
            $("#modal-progress").modal("hide");
        },

        progressall: function (e, data) {  #/* 4. UPDATE THE PROGRESS BAR */
            var progress = parseInt(data.loaded / data.total * 100, 10);  ##
            var strProgress = progress + "%";
            $(".progress-bar").css({"width": strProgress});
            $(".progress-bar").text(strProgress);
        },

        done: function (e, data) {
            if (data.result.is_valid) {
                $("#gallery tbody").prepend(
                    "" + data.result.name + ""
                )
            }
        }
    });
});
注:What we are doing here basically is :
showing the loading modal when the upload starts, 
closing it when it finalizes, 
meanwhile we update the percentage in the progress bar.

2.3. Drag and Drop Upload

Django高级(七):多文件上传_第4张图片
http://127.0.0.1:8000/UploadMulti/drag-and-drop-upload/
##### views.py
一样




##### index.html

{# ### 这里是差异,显示拖拽位置部分,不在是‘Upload photos’按钮 #}

Drop Photos Here to Upload

##### drag-and-drop-upload.js 一样

提交到github

$ cd /root/suyn_website
# 因为Git是分布式版本控制系统,所以每个机器都必须自报家门:你的名字和Email地址。
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"

$ git init  #把当前目录变成Git可以管理的仓库,生成的.git目录(Git的版本库),是Git来跟踪管理版本库的。

$ git add uploadFiles/  #把xx添加到仓库

## 跳到uploadFiles目录里执行以下命令:
$ git commit -m "first commit to my github"  #把xx提交到仓库

## Before below:在GitHub创建同名空仓库
$ git remote add origin [email protected]:userName/uploadFiles.git

# 把当前分支master(默认)推送到远程,远程库的名字就是origin(默认)
$ git push -u origin master

注:源码请参考GitHub-uploadFiles

你可能感兴趣的:(Django高级(七):多文件上传)