通過Django的form及Ajax等多種方式上傳檔案
如下效果:
方式一、通過Django的Form方式上傳檔案
思路:前臺html建立Form,根據格式要求完善form內標籤屬性;提交後臺後,後臺獲取前臺傳來的資料進行處理:檔案路徑儲存至資料庫,檔案內容儲存至本地資料夾中;後臺處理完成後重新整理前臺頁面。
1、建立空白Django專案,過程忽略。
2、靜態html頁面設定:
<form action="/upload.html" method="post" enctype="multipart/form-data"> <input type="text" name="fileName"> <input type="file" name="fileContent"> <input type="submit" value="提交"> </form>
寫一個form表單,三個關鍵標籤:text、file、submit,分別存新的檔名、檔案內容、提交按鈕,由於是檔案上傳因此form中enctype需要設定成multipart/form-data。
3、views後臺設定:
from django.shortcuts import render,redirect import os def Upload(request): if request.method=="GET": return render(request,"upload.html") elif request.method=="POST": # 獲取普通input標籤值,即檔名 filname=request.POST.get('fileName') # 獲取file型別的input標籤值,即檔案內容 file=request.FILES.get('fileContent') # 獲取檔案字尾名 postfix=file.name.split('.')[1] # 設定本地檔案路徑 file_path=os.path.join('static',filname+'.'+postfix) # 將上傳的檔案寫入本地目錄 f=open(file_path,"wb") for chunk in file.chunks(): f.write(chunk) f.close() return redirect("upload.html")
url檔案配置:
from Upload import views
urlpatterns = [
path('upload.html',views.Upload),
]
原理:
(1)、當Get請求時,即瀏覽器開啟該網頁時,顯示上傳頁面;
(2)、當POST請求時,即點選“提交”按鈕時:
①、獲取介面傳過來的新的檔名及檔案內容。
②、分塊讀取檔案內容,並寫入到本地目錄。
4、頁面上動態顯示剛剛上傳的圖片,需做如下改造:
(1)、新建資料庫表,用來儲存圖片路徑:
# 圖片類 class image(models.Model): # 路徑 file_Path=models.CharField(max_length=32)
(2)、在上傳成功時將檔案路徑儲存至資料庫,即在views的檢視方法的POST中的儲存檔案後面新增程式碼:
# 寫入成功後將路徑儲存至資料庫
models.image.objects.create(file_Path=file_path)
(3)、頁面重新整理時展現圖片,即在檢視方法的GET中讀取資料庫中新增的圖片路徑,並將其返給html頁面:
if request.method=="GET":
# 獲取所有圖片
imgs=models.image.objects.all()
return render(request,"upload.html",{"imgs":imgs})
(4)、html頁面中增加
<div class="imgs">
{% for obj in imgs %}
<img src="{{ obj.file_Path }}">
{% endfor %}
</div>
(5)、由於Django對靜態檔案瀏覽的限制,需要在配置中新增:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static"),
]
方式二、通過原生js實現
思路:html頁面,通過FormData承載圖片內容,並通過原生的XMLHttpRequest將頁面全部資訊傳輸到後臺views中;後臺views接收後處理並將結果通過json形式返回給前臺html頁面;前臺html頁面接收到字串內容後轉換為json物件;建立圖片標籤,並將接收到的圖片地址賦值。
1、url配置如下:
from Upload import views
urlpatterns = [
path('uploadjs.html', views.Upload_js),
]
2、views檢視函式:
def Upload_js(request):
if request.method == "GET":
# 獲取所有圖片
imgs = models.image.objects.all()
return render(request, "upload_js.html", {"imgs": imgs})
elif request.method == "POST":
# 獲取普通input標籤值,即檔名
filname = request.POST.get('fileName')
# 獲取file型別的input標籤值,即檔案內容
file = request.FILES.get('fileContent')
# 獲取檔案字尾名
postfix = file.name.split('.')[1]
# 設定本地檔案路徑
file_path = os.path.join('static', filname + '.' + postfix)
# 將上傳的檔案寫入本地目錄
f = open(file_path, "wb")
for chunk in file.chunks():
f.write(chunk)
f.close()
# 寫入成功後將路徑儲存至資料庫
models.image.objects.create(file_Path=file_path)
#將狀態及檔案路徑通過json形式返回至html頁面
ret={'status':True,'path':file_path}
return HttpResponse(json.dumps(ret))
3、前臺html頁面
<body>
<input type="text" name="fileName" id="fileName">
<input type="file" name="fileContent" id="fileContent">
<input type="button" value="提交" onclick="upload();">
<div class="imgs">
{% for obj in imgs %}
<img src="{{ obj.file_Path }}">
{% endfor %}
</div>
<script>
function upload() {
//建立FormData用於儲存檔案內容
var dict=new FormData();
dict.append("fileName",document.getElementById('fileName').value);
dict.append("fileContent",document.getElementById('fileContent').files[0]);
var xml=new XMLHttpRequest();
//uploadjs.html即url.py中配置的後臺views
xml.open("post",'/uploadjs.html',true);
xml.onreadystatechange=function(){
if (xml.readyState==4 && xml.status==200) {
//傳輸成功時將檢視返回回來的內容通過json接收
var obj=JSON.parse(xml.responseText);
if(obj.status){
//建立圖片標籤,並將後臺傳回來的圖片地址加上,顯示在頁面中
var img=document.createElement('img');
img.src='/'+obj.path;
document.getElementsByClassName('imgs')[0].appendChild(img);
}
}
};
xml.send(dict)
}
</script>
</body>
方式三、通過JQuery實現
原理:將方式二中原生js部分改為JQuery形式,其他無變化。
html頁面程式碼如下:
<body>
<input type="text" name="fileName" id="fileName">
<input type="file" name="fileContent" id="fileContent">
<input type="button" value="提交" onclick="upload();">
<div class="imgs">
{% for obj in imgs %}
<img src="{{ obj.file_Path }}">
{% endfor %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
function upload() {
//建立FormData用於儲存檔案內容
var dict=new FormData();
dict.append("fileName",document.getElementById('fileName').value);
dict.append("fileContent",document.getElementById('fileContent').files[0]);
$.ajax({
url:'/uploadjq.html',
type:'post',
data:dict,
processData: false,// 告訴jQuery不要去處理髮送的資料(必須設定)
contentType: false, // 告訴jQuery不要去設定Content-Type請求頭(必須設定)
dataType:'JSON',
success:function (arg) {
if(arg.status){
//建立圖片標籤,並將後臺傳回來的圖片地址加上,顯示在頁面中
var img=document.createElement('img');
img.src='/'+arg.path;
$('.imgs')[0].appendChild(img);
}
}
})
}
</script>
</body>
注意:由於使用的是FormData物件,需要將processData、contentType設定成false,至於為什麼要這麼設定,詳見:
方式四、通過iframe及form表單,views後臺程式碼與方式二一致
原理:將views後臺返回的資料傳給iframe頁面標籤,觸發iframe的onload事件時實現img圖片動態載入。
1、原生js時,獲取iframe物件內容通過document.getElementById('iframe的ID').contentWindow.document.getElementById('元素的ID');contentWindow代表frame和iframe內部的視窗物件。html前臺頁面如下:
<body>
<form action="/uploadiframe.html" method="post" enctype="multipart/form-data" target="img_igrame">
<iframe id="img_igrame" name="img_igrame" onload="loadiframe(this)" ></iframe>
<input type="text" name="fileName">
<input type="file" name="fileContent">
<input type="submit" value="提交">
</form>
<div class="imgs">
{% for obj in imgs %}
<img src="{{ obj.file_Path }}">
{% endfor %}
</div>
<script>
function loadiframe(self) {
// 獲取iframe內部的內容
var str_json=self.contentWindow.document.getElementsByTagName('body')[0].innerText;
var obj = JSON.parse(str_json);
if (obj.status){
var img = document.createElement('img');
img.src = "/" + obj.path;
document.getElementsByClassName('imgs')[0].appendChild(img);
}
}
</script>
</body>
2、jQuery時,通過.contents() 方法;.contents() 方法允許我們檢索 DOM 樹中的這些元素的直接子節點,並用匹配元素構造新的 jQuery 物件。.contents() 和 .children() 方法類似,不同的是前者在結果 jQuery 物件中包含了文字節點以及 HTML 元素。.contents() 方法也可以用於獲得 iframe 的內容文件,前提是該 iframe 與主頁面在同一個域。程式碼如下:
<body>
<form action="/uploadiframe.html" method="post" enctype="multipart/form-data" target="img_igrame">
<iframe id="img_igrame" name="img_igrame" onload="loadiframe(this)" ></iframe>
<input type="text" name="fileName">
<input type="file" name="fileContent">
<input type="submit" value="提交">
</form>
<div class="imgs">
{% for obj in imgs %}
<img src="{{ obj.file_Path }}">
{% endfor %}
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
function loadiframe(self) {
// 獲取iframe內部的內容
var str_json = $('#img_igrame').contents().find('body').text();
var obj = JSON.parse(str_json);
if (obj.status){
var img = document.createElement('img');
img.src = "/" + obj.path;
$('#imgs').append(img);
}
}
</script>
</body>
=======
總結:
通過Django的Form方式上傳檔案,簡單,但無法區域性重新整理實現ajax效果;
通過js或jQuery方式,需要使用FormData物件,仍有些瀏覽器不相容;
通過Form+iframe方式上傳檔案,相容性最好。