1. 程式人生 > >Django的AJAX實現之檔案上傳

Django的AJAX實現之檔案上傳

Uploadify元件上傳檔案很酷,可以實現檔案進度上傳,而且可以批量上傳各種檔案。好處還很多,具體詳情登到官網看看文件瞭解吧。在同類元件中,Uploadify做的也很出色。打算在Django中用它,兩個東西結合使用,也算簡單,但有些細節需要記下來,以便以後重用。

這次只說上傳圖片部分,至於上傳檔案,其實可以照貓畫虎,而且來得會簡單些,只是python程式後端寫法的區別而已,前端程式碼Uploadify一律平等對待,圖片也是檔案一種特例罷了。

Django使用Uploadify元件實現圖片上傳,可以分為兩個大步驟。
一:前端引用Uploadify所需要的類庫和指令碼樣式。
Uploadify會用到JQuery類庫,還有自己的幾個指令碼和樣式檔案,搭配好了Django的靜態檔案,讓Django正確解析靜態檔案,就算成功一半了,靜態檔案的配置參考先前的部落格:《

Django靜態檔案的配置》。

靜態檔案我們統一存放在根目錄的site_media資料夾下,到官網http://www.uploadify.com/下載Uploadify-2.14元件,放在site_media下的plugin,隨意起名:uploadify_214,再新建個檔案下upload,來存放上傳的圖片。

前端樣式指令碼引用程式碼:

  1. <linkhref="/site_media/plugin/uploadify_214/uploadify.css"type="text/css"rel="stylesheet"/>
  2. <scripttype="text/javascript"src="/site_media/js/jquery.js"
    ></script>
  3. <scripttype="text/javascript"src="/site_media/plugin/uploadify_214/swfobject.js"></script>
  4. <scripttype="text/javascript"src="/site_media/plugin/uploadify_214/jquery.uploadify.v2.1.4.min.js"></script>

引用檔案的路徑算是很重要,具體靜態配置決定這些。首先引用Uploadify的樣式檔案,然後就是先引用JQuery類庫,再引用Uploadify自身指令碼swfobject.js和jquery.uploadify.v2.1.4.min.js

Uploadify元件初始化程式碼:

  1. <script type="text/javascript">  
  2. $(document).ready(function() {  
  3.   $('#file_upload').uploadify({  
  4.     'uploader'  : '/site_media/plugin/uploadify_214/uploadify.swf',  
  5.     'script'    : '{%url uploadify_script%}',  
  6.     'cancelImg' : '/site_media/plugin/uploadify_214/cancel.png',  
  7.     'folder'    : '/upload',  
  8.     'auto'      : false,//
  9.     'multi'true,//設定可以上傳多個檔案
  10.     'queueSizeLimit':20,//設定可以同時20個檔案
  11.     'removeCompleted':false,//
  12.     'sizeLimit':10240000,//設定上傳檔案大小單位kb
  13.     'fileExt':'*.jpg;*.gif;*.png',//設定上傳檔案型別為常用圖片格式
  14.     'fileDesc':'Image Files',                  
  15.     'onInit'function () {},  
  16.     'onError' : function (event,ID,fileObj,errorObj) {  
  17.             $('#id_span_msg').html("上傳失敗,錯誤碼:"+errorObj.type+" "+errorObj.info);  
  18.         },  
  19.     'onSelect'function (e, queueId, fileObj) {  
  20.         $('#id_span_msg').html("");  
  21.     },  
  22.     'onAllComplete'function (event, data) {  
  23.         if(data.filesUploaded>=1){  
  24.           $('#id_span_msg').html("上傳成功!");  
  25.         }                      
  26.     }                  
  27.   });  
  28. });  
  29. </script>  

初始化指令碼,有幾個關鍵的引數需要說明一下:
uploader是元件需要flash編譯檔案,裡面封裝了Uploadify核心的處理程式。
script是後端上傳檔案程式的url,這個是後面說的,需要自己寫。
folder是上傳檔案的目錄,這裡我們不計劃使用它,隨便寫一個充數。

前端html程式碼

  1. <h1>Uploadify元件上傳方式</h1>
  2. <divclass="demo-box">
  3.     <inputid="file_upload"type="file"name="Filedata">
  4.     <divid="file_uploadQueue"class="uploadifyQueue"></div>
  5.     <p><ahref="javascript:$('#file_upload').uploadifyUpload()">上傳圖片</a>
  6.     <ahref="javascript:$('#file_upload').uploadifyClearQueue()">取消上傳</a>
  7.     </p>
  8.     <p><spanid="id_span_msg"></span></p>
  9. </div>


二:寫好後端圖片上傳的方法。
如果剛開始就把寫好的上傳程式和Uploadify結合,也許不是很明智的做法,因為過程中遇到問題,我們不很確定是後端程式的bug還是Uploadify的配置錯誤,所以建議先把寫好的後端上傳程式,用傳統的上傳方式,去測試,把程式除錯好了,再和Uploadify結合,這樣就會很清楚是那塊出現問題了。
所以我們先寫個通用的上傳函式_upload,用傳統的上傳方式測試它,該函式:

  1. def _upload(file):  
  2.     '''''圖片上傳函式'''
  3.     if file:              
  4.         path=os.path.join(settings.MEDIA_ROOT,'upload')  
  5.         file_name=str(uuid.uuid1())+".jpg"
  6.         path_file=os.path.join(path,file_name)  
  7.         parser = ImageFile.Parser()    
  8.         for chunk in file.chunks():    
  9.             parser.feed(chunk)    
  10.         img = parser.close()  
  11.         try:  
  12.             if img.mode != "RGB":  
  13.                 img = img.convert("RGB")  
  14.             img.save(path_file, 'jpeg',quality=100)  
  15.         except:  
  16.             returnFalse
  17.         returnTrue
  18.     returnFalse


這個程式接收一個Files物件,在記憶體裡處理儲存好圖片,程式就幾行程式碼就不解釋太多了。大體是先構造一個實體地址用於儲存圖片,再把記憶體裡的圖片資訊存入img臨時變數中,判斷圖片的模式,如果不是RGB,轉換,儲存成jpg格式,返回True,失敗返回False。
該函式測試通過了,能完成儲存圖片的使命,最後就是寫Uploadify需要的函式uploadify_script

  1. @csrf_exempt
  2. def uploadify_script(request):  
  3.     response=HttpResponse()  
  4.     response['Content-Type']="text/javascript"
  5.     ret="0"
  6.     file = request.FILES.get("Filedata",None)          
  7.     if file:              
  8.         if _upload(file):  
  9.             ret="1"
  10.         ret="2"
  11.     response.write(ret)  
  12.     return response  


Uploadify使用uploadify_script函式,通過Get方式把圖片控制元件的資訊提交給該函式,函式返回"text/javascript"的內容型別,如果成功寫入字元1,否則寫入非1字元。頁面的圖片控制元件命名Filedata,Django通過file = request.FILES.get("Filedata",None)獲取控制元件的圖片資訊,如果不是空的,就傳遞給剛才說的通用函式_upload,儲存圖片。


整個過程算是完結了,過程中值得注意的:
1 常常出現IO Error,如果我們已經測試_upload和uploadify_script後端程式,他們都沒有錯誤,很多程度上是因為前端的Uploadify初始化指令碼的問題,確認Uploadify幾個關鍵的引數能不能正確解析,或者是靜態檔案配置沒成功造成的。
2 Forbidden (403)這是Django引發的,Django1.3引進了CSRF,我們需要進行一些處理,給uploadify_script一個裝飾器@csrf_exempt,記住這個很關鍵,很折騰人。
3 cannot write mode P as JPEG,這個是後端上傳程式的錯誤,是因為上傳了非jpg型別的圖片,我們需要需要轉換成RGB,再儲存,上面已經提過。