天天看點

Django的form表單之檔案上傳

在生成input标簽的時候可以指定input标簽的類型為file類型

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h4>{{ error_message }}</h4>
<form action="/index/" method="post">
    {% csrf_token %}
    <p><input type="file" name="up_file"></p>
    <input type="submit">
</form>
</body>
</html>           

此時,在網頁上頁示如下

Django的form表單之檔案上傳

如果網頁上送出的是使用者名和密碼等,通過鍵值對發送到服務端。

一組鍵值代表一個标簽及标簽對應的值。

在網頁上選擇一張圖檔,并使用

post

方式送出,在服務端列印

request.POST

def index(request):
        if request.method=="POST":
            print(request.POST)
    
        return render(request,"index.html",locals())
               

列印的資訊如下:

<QueryDict: {'csrfmiddlewaretoken': ['opmSmENIrgdGJJN'], 'up_file': ['1.png']}>           

送出的檔案名也在這個字典中,取出這個檔案名

def index(request):
        if request.method=="POST":
            print(request.POST.get("up_file"))
            print(type(request.POST.get("up_file")))
    
        return render(request,"index.html",locals())
               

列印結果如下:

1.png
<class 'str'>           

想取出的是上傳的檔案,然而取出來的卻是上傳的檔案的檔案名

由此可知,上傳的檔案沒有跟form表單送出的資料在一起

因為上傳的檔案通常大小比較大,是以Django預設會把上傳的檔案放在一個具體的檔案夾中

列印

request.FILES

的資訊

def index(request):
        if request.method=="POST":
            print(request.POST.get("up_file"))
            print(type(request.POST.get("up_file")))
            print("files:",request.FILES)
    
        return render(request,"index.html",locals())           

列印結果如下

1.png
<class 'str'>
files: <MultiValueDict: {}>           

request.FILES

列印的結果是一個空的字典,問題出在上傳檔案的方式上

由于上傳檔案時在用戶端與服務端傳輸的是二進制資料,與字元串資料不一樣。

傳輸二進制資料,不管是在form表單,還是在Ajax中,都有自己的傳輸方式。

在form表單中,上傳檔案時要使用分片傳輸的方式。

修改index.html檔案

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h4>{{ error_message }}</h4>
<form action="/index/" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <p><input type="file" name="up_file"></p>
    <input type="submit">
</form>
</body>
</html>           

重新上傳檔案,在服務端列印資訊如下

None
<class 'NoneType'>
files: <MultiValueDict: {'up_file': [<InMemoryUploadedFile: 1.png (image/png)>]}>           

根據列印結果,

request.FILES

中可以看到上傳的檔案

列印結果是一個字典類型,字典的鍵是form表單中定義的标簽的name屬性值,而其值是所上傳的檔案的對象

列印上傳檔案的對象

def index(request):
    if request.method=="POST":

        print("files:",request.FILES.get("up_file"))
        print(type(request.FILES.get("up_file")))

    return render(request,"index.html",locals())           

列印結果

files: 1.png
<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>           

結果顯示所取得的檔案的類型是一個在記憶體中的上傳檔案

擷取上傳檔案在記憶體中的名字

def index(request):
    if request.method=="POST":

        print(type(request.FILES.get("up_file")))

        file_obj=request.FILES.get("up_file")

        print(file_obj.name)


    return render(request,"index.html",locals())           
<class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
1.png           

既然知道了檔案在記憶體中的名字,就可以在服務端寫入這個檔案

def index(request):
    if request.method=="POST":
        file_obj=request.FILES.get("up_file")

        f1=open(file_obj.name,"wb")

        for i in file_obj.chunks():
            f1.write(i)

        f1.close()

    return render(request,"index.html",locals())           

再次選擇上傳檔案,送出後,就可以在服務端背景看到所上傳的檔案

可以在settings.py檔案中設定上傳檔案的路徑,或者在打開檔案句柄的時候進行路徑拼接來把上傳的檔案儲存在指定的目錄下