文件上傳

1、上傳到本身的服務器:css

 

使用 AdminLTE 2 網站中的 form 表單的代碼:https://adminlte.io/themes/AdminLTE/pages/forms/general.html (使用其原先css樣式及HTML代碼,代碼內容通過精簡)html

 

前端代碼:前端

 

首先:一個帶有輸入框跟上傳按鈕的HTML文件(樣式圖以下:)python

1 <div class="form-group">
2     <label for="thumbnail-form">縮略圖</label>
3     <div class="input-group">
4         <input type="text" class="form-control" id="thumbnail-form" name="thumbnail">
5         <span class="input-group-btn">
6             <input type="file" class="btn btn-default" id="thumbnail-btn" value="上傳文件">
7         </span>
8     </div>
9 </div>
View Code

使用 input標籤 , type=file 時顯示的樣式;jquery

 

將上圖修改成下圖的樣式,使其更美觀;git

 1 <div class="form-group">
 2     <label for="thumbnail-form">縮略圖</label>
 3     <div class="input-group">
 4         <input type="text" class="form-control" id="thumbnail-form" name="thumbnail">
 5         <span class="input-group-btn">
 6             <label class="btn btn-default btn-file">
 7                 上傳圖片<input  hidden type="file" class="btn btn-default" id="thumbnail-btn">
 8             </label>
 9         </span>
10     </div>
11 </div>
View Code

id = "thumbnail-form":輸入框的ID;github

id = "thumbnail-btn":做爲隱藏起來的 file標籤 文件的一個按鈕ID;ajax

使用 label標籤,其中 for 中的值等於 input 的ID至關於點擊「縮略圖」時會默認點擊下方輸入框;點擊「上傳圖片」會默認點擊「type=file」的標籤;兩者之間存在關聯;django

使用 hidden 將 file標籤 隱藏起來,使「上傳圖片」的字體將其覆蓋;json

 

使用js文件監聽其上傳時的點擊事件;

 1 function News() {
 2 
 3 }
 4 
 5 News.prototype.run = function () {
 6     var self = this;
 7     self.ListenUploadFileEvent();
 8 };
 9 
10 // 監聽文件上傳的事件;
11 News.prototype.ListenUploadFileEvent = function () {
12     var uploadBtn = $('#thumbnail-btn');
13     uploadBtn.change(function () {
14         var file = uploadBtn[0].files[0];
15         var formData = new FormData();
16         formData.append('file', file);
17         xfzajax.post({
18             'url': '/cms/upload_file/',
19             'data': formData,
20             'processData': false,
21             'contentType': false,
22             'success': function (result) {
23                 if (result['code'] === 200){
24                     var url = result['data']['url'];
25                     var thumbnailInput = $('#thumbnail-form');
26                     thumbnailInput.val(url);
27                 }
28             }
29         })
30     });
31 };
32 
33 $(function () {
34     var news = new News();
35     news.run();
36 });
View Code

 

change:用來監聽進入上傳文件選定文件後點擊打開按鈕的事件,此處不能使用 click 點擊事件;

由於 uploadBtn 獲得的是一個集合,不是一個單一的對象。因此 var file = uploadBtn[0].files[0]; 中的 uploadBtn[0] 用來獲取其中的惟一一個按鈕,與其存儲的全部文件中的第一個文件。

formData:用來存儲文件;

 formData.append('file', file); :引號中的字段名需與後臺經過 ‘get’ 獲取文件填寫的字段名保持一致;

而後經過ajax請求發送給後端服務器,跳轉的 url 及其數據 formData,後兩個 false  爲告知上層 jquery-3.3.1.min.js 文件不對該文件的數據再次進行處理或添加其它內容,以及成功或者失敗的返回內容(失敗內容定義在ajax文件中);

在後端中獲得的url完整路徑,調用 ‘restful’ 中的 ‘result’ 函數,再將獲取的 ‘url’ 的值給到前端輸入框中顯示。

 

ajax代碼

 1 //static:xfzajax.js
 2 function getCookie(name) {
 3     var cookieValue = null;
 4     if (document.cookie && document.cookie !== '') {
 5         var cookies = document.cookie.split(';');
 6         for (var i = 0; i < cookies.length; i++) {
 7             var cookie = jQuery.trim(cookies[i]);
 8             // Does this cookie string begin with the name we want?
 9             if (cookie.substring(0, name.length + 1) === (name + '=')) {
10                 cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
11                 break;
12             }
13         }
14     }
15     return cookieValue;
16 }
17 
18 var xfzajax = {
19     'get': function (args) {
20         args['method'] = 'get';
21         this.ajax(args);
22     },
23     'post': function (args) {
24         args['method'] = 'post';
25         this._ajaxSetup();
26         this.ajax(args);
27     },
28     'ajax': function (args) {
29         var success = args['success'];
30         args['success'] = function (result) {
31             if (result['code'] === 200) {
32                 if (success) {
33                     success(result)
34                 }
35             } else {
36                 var messageObject = result['message'];
37                 if (typeof messageObject == 'string' || messageObject.constructor === String) {
38                     window.messageBox.showError(messageObject);
39                 } else {
40                     // {"password":['密碼最大長度不能超過20爲!','xxx'],"telephone":['xx','x']}
41                     for (var key in messageObject) {
42                         var messages = messageObject[key];
43                         var message = messages[0];
44                         window.messageBox.showError(message);
45                     }
46                 }
47                 if(success){
48                     success(result)
49                 }
50             }
51         };
52         args['fail'] = function (error) {
53             console.log(error);
54             window.showError('服務器內部錯誤!')
55         };
56         $.ajax(args);
57     },
58     '_ajaxSetup': function () {
59         $.ajaxSetup({
60             beforeSend: function (xhr, settings) {
61                 if (!/^(GET|HEAD|OPTIONS|TRACE)$/.test(settings.type) && !this.crossDomain) {
62                     xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
63                 }
64             }
65         });
66     }
67 };
View Code

 

 

後端代碼:

 

settings.py文件的設置:

1 # 在末尾添加內容;
2 
3 STATIC_URL = '/static/'
4 STATICFILES_DIRS = [
5     os.path.join(BASE_DIR,'front','dist'),
6 ]
7 
8 MEDIA_URL = '/media/'
9 MEDIA_ROOT = os.path.join(BASE_DIR,'media')
View Code

使用MEDIA_ROOTMEDIA_URL,用來指定文件上傳後存儲的位置,在主目錄中新建‘media’文件用來存儲內容;

 

文件的映射路徑,與前端 ajax 內容中跳轉的 url 一致。

 1 # 總的url連接;
 2 
 3 from django.urls import path,include
 4 from django.conf.urls.static import static
 5 from django.conf import settings
 6 
 7 urlpatterns = [
 8     path('cms/',include('apps.cms.urls')),
 9 ] + static(settings.MEDIA_URL,document_root=settings.MEDIA_ROOT)
10 
11 
12 # cms的url:
13 
14 from django.urls import path
15 from . import views
16 
17 app_name = 'cms'
18 
19 urlpatterns = [
20     path('upload_file/',views.upload_file,name='upload_file'),
21 ]
View Code

 

視圖函數

 1 from django.views.decorators.http import require_POST, 
 2 from utils import restful
 3 from django.conf import settings
 4 import os
 5 
 6 
 7 # 文件上傳;
 8 @require_POST
 9 def upload_file(request):
10     file = request.FILES.get('file')
11     name = file.name
12     with open(os.path.join(settings.MEDIA_ROOT,name),'wb') as fp:
13         for chunk in file.chunks():
14             fp.write(chunk)
15     url = request.build_absolute_uri(settings.MEDIA_URL + name)
16     return restful.result(data={'url':url})
View Code

使用 「get」 獲取的 「file」 與前端提到 「file」 一致;

使用 build_absolute_uri 能夠獲取完整的url地址;

 

restful.py文件(簡化每一個文件代碼運行結果的代碼量)

 1 from django.http import JsonResponse
 2 
 3 class HttpCode(object):
 4     ok = 200            # 正常運行;
 5     paramserror = 400   # 參數錯誤;
 6     unauth = 401        # 沒受權;
 7     methoderror = 405   # 請求方法錯誤;
 8     servererror = 500   # 服務器內部錯誤;
 9 
10 def result(code=HttpCode.ok,message='',data=None,kwargs=None):
11     json_dict = {'code':code,'message':message,'data':data}
12     if kwargs and isinstance(kwargs,dict) and kwargs.keys():
13         json_dict.update(kwargs)
14     return JsonResponse(json_dict)
15 
16 def ok():
17     return result()
18 
19 def params_error(message='',data=None):
20     return result(code=HttpCode.paramserror,message=message,data=data)
21 
22 def unauth(message='',data=None):
23     return result(code=HttpCode.unauth,message=message,data=data)
24 
25 def method_error(message='',data=None):
26     return result(code=HttpCode.methoderror,message=message,data=data)
27 
28 def server_error(message='',data=''):
29     return result(code=HttpCode.servererror,message=message,data=data)
View Code

 

 

2、上傳到七牛雲

 

一、登陸註冊七牛雲:https://www.qiniu.com//

二、登陸後進入右上方管理控制檯後,再點擊右上角的我的圖標進入密鑰管理,記住 AK 與 SK ,後續用到;

三、點擊左側 對象存儲,新建存儲空間 bucket 

 

後端:

 

一、下載 python SDKpip install qiniu

二、建立一個獲取 tokenurl

 1 # 上傳七牛雲;
 2 @require_GET
 3 def qntokon(request):
 4     access_key = 'GjdN0XJxtrLbINSxx4ZjXXitk7Aux5h046x9viB8'
 5     secret_key = '8ULlOQezsKZIRFl_Bie09GZIJyonH50aJH6RONhu'
 6     bucket = 'qmspace'
 7     # 建立受權信息q;
 8     q = qiniu.Auth(access_key,secret_key)
 9     # 生成上傳憑證,傳給前端;
10     tokon = q.upload_token(bucket)
11     return restful.result(data={'tokon':tokon})
View Code

 

前端:

 

基於七牛 API 開發的前端 JavaScript SDK:https://github.com/qiniu/js-sdk(詳細的官方文檔講解)

 

在HTML代碼的縮略圖代碼下添加進度條代碼,默認隱藏;

 1 <!--html代碼-->
 2 <script src="https://unpkg.com/qiniu-js@2.4.0/dist/qiniu.min.js
 3 "></script>
 4 --snip--
 5 <div class="form-group">
 6     <label for="thumbnail-form">縮略圖</label>
 7     --snip--
 8     </div>
 9 </div>
10 <!--上傳進度條-->
11 <div class="form-group" id="progress-group" style="display: none;">
12     <div class="progress">
13       <div class="progress-bar progress-bar-info" role="progressbar" aria-valuenow="20"
14            aria-valuemin="0" aria-valuemax="100" style="width: 0">
15           0%
16       </div>
17     </div>
18 </div>
View Code

 

經過 js 代碼實現與七牛雲的對接及文件的上傳,以及進度條的顯示狀況;

 1 // 上傳到七牛雲;
 2 News.prototype.ListenQiniuuploadFileEvent = function(){
 3     var self = this;
 4     var uploadBtn = $('#thumbnail-btn');
 5     uploadBtn.change(function () {
 6         var file = this.files[0];
 7         xfzajax.get({
 8             'url': '/cms/qntokon/',
 9             'success': function (result) {
10                 if (result['code'] ===200 ){
11                     
12                     // token: 上傳驗證信息,前端經過接口請求後端得到;
13                     var tokon = result['data']['tokon'];
14                     
15                     // key: 文件資源名(當前時間+文件格式);
16                     var key = (new Date()).getTime() + '.' + file.name.split('.')[-1];
17                     
18                     var putExtra = {
19                         fname: key,
20                         params: {},
21                         mimeType: ['image/png','image/jpeg','image/gif','video/x-ms-wmv','video/mp4','video/x-flv']
22                     };
23                     
24                     var config = {
25                         useCdnDomain: true,
26                         retryCount: 6,
27                         region: qiniu.region.z2
28                     };
29                     
30                     // 文件上傳;
31                     var observable = qiniu.upload(file,key,tokon,putExtra,config);
32                     observable.subscribe({
33                         'next': self.handFileUploadProcess,
34                         'error': self.handFileUploadError,
35                         'complete': self.handFileUploadComplete,
36                     })
37                 }
38             }
39         })
40     })
41 };
42 
43 News.prototype.handFileUploadProcess = function(response){
44     var total = response.total;
45     var percent = total.percent;
46     var percentText = percent.toFixed() + '%';
47     var progressGroup = News.progressGroup;
48     progressGroup.show();
49     var progressBar = $('.progress-bar');
50     progressBar.css({"width":percentText});
51     progressBar.text(percentText);
52 };
53 
54 News.prototype.handFileUploadError = function(error){
55     window.messageBox.showError(error.message);
56     var progressGroup = News.progressGroup;
57     progressGroup.hide();
58     console.log(error.message);
59 };
60 
61 News.prototype.handFileUploadComplete = function(response){
62     console.log(response);
63     var progressGroup = News.progressGroup;
64     progressGroup.hide();
65     var domain = 'http://ps96zui1h.bkt.clouddn.com/';
66     var filename = response.key;
67     var url = domain + filename;
68     var thumbnailInput = $("input[name='thumbnail']");
69     thumbnailInput.val(url)
70 };
71 
72 $(function () {
73     var news = new News();
74     news.run();
75     News.progressGroup = $('#progress-group');
76 });
View Code

(官方文檔很詳細,再也不作我的註解)

 

上傳成功:

相關文章
相關標籤/搜索