Django檔案上傳和圖片上傳
檔案上傳:
檔案上傳是網站開發中非常常見的功能。接下來就將詳細講述如何在Django中實現檔案的上傳功能。
前端HTML程式碼實現:
- 在前端中,我們需要填入一個form標籤,然後在這個form標籤中指定enctype=“multipart/form-data”,不然就不能上傳檔案。
- 在form標籤中新增一個input標籤,然後指定input標籤的name(
即上傳檔案我們想要它顯示的名字
),以及type=“file”。
新建一個file.html的檔案,body中寫入:
<form action="" method="post" enctype ="multipart/form-data">
<input type="file" name="myfile">
<input type="submit" value="提交">
</form>
後端的程式碼實現:
後端的主要工作是接收檔案。然後儲存檔案。接收檔案的方式跟接收POST的方式是一樣的,只不過是通過FILES來實現。示例程式碼如下:
在views中新增檢視函式:
from django.shortcuts import render
from django.views.generic import View
from django.http import HttpResponse
# Create your views here.
class IndexView(View):
def get(self,request):
return render(request,'file.html')
def post(self,request):
myfile = request.FILES.get('myfile')
with open('files.txt','wb') as fp:
for chunk in myfile. chunks():
fp.write(chunk)
return HttpResponse('success')
然後在urls中新增對映,我們就可以執行專案了,
然後我們就可以選取本地的檔案進行上傳了。
使用模型來處理上傳的檔案:
在定義模型的時候,我們可以給儲存檔案的欄位指定為FileField,這個Field可以傳遞一個upload_to引數,用來指定上傳上來的檔案儲存到哪裡。比如我們讓他儲存到專案的files資料夾下,那麼示例程式碼如下:
在models中新建一個模型:
from django.db import models
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
file = models.FileField(upload_to='files')
因為我們指定了上傳到files
資料夾中,所以我們需要手動在專案的根目錄下新建一個資料夾files
,然後在檢視中新增檢視:
from .models import Article
class ArticleView(View):
def get(self,request):
return render(request,'file.html')
def post(self,request):
title = request.POST.get('title')
content = request.POST.get('content')
file = request.FILES.get('myfile')
Article.objects.create(title=title,content=content,file=file)
return HttpResponse('success')
這裡我們繼續渲染的時上面那個示例的模板,所以我們需要在上面的模板中新增兩個input標籤,在file.html中的body中寫入:
<form action="" method="post" enctype="multipart/form-data">
<input type="text" name="title"><br>
<input type="text" name="content"><br>
<input type="file" name="myfile"><br>
<input type="submit" value="提交"><br>
</form>
然後我們在urls中新增對映,就能夠正常的進行訪問了。
注意: 在資料庫中file欄位儲存的是檔案的路徑,而不是檔案的資訊。
指定MEDIA_ROOT和MEDIA_URL:
1. MEDIA_ROOT
上面我們是使用了upload_to來指定上傳的檔案的目錄。我們也可以指定MEDIA_ROOT,就不需要在FielField中指定upload_to,他會自動的將檔案上傳到MEDIA_ROOT的目錄下。
在settingsz.py中最下面新增程式碼:
# 指定上傳的檔案存放位置
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
# 獲取上傳的檔案的url
MEDIA_URL = '/media/'
然後我們將上面的files資料夾修改一個檔名為media
。並且可以將file欄位中的upload_to引數也去掉。
這樣,我們也能將檔案上傳至我們指定的media目錄下。
但是,這樣就產生了一個問題,隨著網站越來越大,那麼檔案上傳的次數肯定也多了,全部都放在media目錄下不方便我們管理。所以者惡搞時候我們可以對檔案儲存的位置進一步劃分。
我們在file欄位中繼續傳入一個引數upload_to
file = models.FileField(upload_to='files')
這樣,因為我們在settings中設定了MEDIA_ROOT引數,所以Django會先去查詢MEDIA_ROOT引數中的值,然後再尋找upload_to中的值,所以最後上傳的檔案的路徑為media/files/< filename >
。
當然我們也可以按照時間來進行儲存,只需要改變upload_to的值就行了。
file = models.FileField(upload_to='%Y/%m/%d/')
然後就會在media下生成一個年/月/日
的資料夾。並且將我們上傳的檔案放入裡面。
2. MEDIA_URL
如果我們想要訪問上傳的檔案,那麼我們直接輸入網址
127.0.0.1:8000/media/<filename>
是訪問不到的,那麼我們應該怎樣來進行訪問呢。
這個時候我們就需要使用到MEDIA_URL
了。
在主urls中新增程式碼
from django.urls import path,include
from django.conf.urls.static import static
# 匯入settings檔案,就能得到settings中的所有東西
from django.conf import settings
urlpatterns = [
path('front/', include('front.urls')),
path('file/',include('file.urls')),
] + static(settings.MEDIA_URL,document_root = settings.MEDIA_ROOT)
這樣,我們就可以像上面那樣輸入網址對檔案進行訪問了。
因為static函式返回的是一個列表,所以我們用+
對他們進行連線,就會把static返回的列表中的值放入urlpatterns這個列表中。如果檔案時圖片也是一樣可以訪問的。
限制上傳的檔案拓展名:
為什麼我們需要限制上傳檔案的副檔名呢,因為如果別人上傳一些字尾名為.py、.php
等檔案,那麼這些檔案是可以被執行的,那麼就對我們的網站存在著極大的安全隱患。所以我們需要限制檔案上傳的字尾名。
如果想要限制上傳的檔案的拓展名,那麼我們就需要用到表單來進行限制。我們可以使用普通的Form表單,也可以使用ModelForm,直接從模型中讀取欄位。
首先修改models中的程式碼,給file欄位新增一個validators
from django.db import models
from django.core import validators
# Create your models here.
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# 只允許上傳txt檔案
file = models.FileField(upload_to='%Y/%m/%d/',validators=[validators.FileExtensionValidator(['txt'],message='file必須為txt檔案')])
然後我們使用modelForm對資料進行驗證,新建一個forms.py檔案,寫入程式碼:
from django import forms
from .models import Article
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__'
然後修改Views中的ArticleView檢視,將裡面的post函式註釋掉,然後重新寫入一個post函式
def post(self,request):
# request.POST,對普通欄位進行驗證
# request.FILES 對檔案欄位進行驗證
form = ArticleForm(request.POST,request.FILES)
if form.is_valid():
form.save()
return HttpResponse('success')
else:
print(form.errors.get_json_data())
return HttpResponse('fail')
因為我們使用的是modelForm,所以前端傳入資料的name屬性一定要和model中的欄位名一樣。所以我們修改file.html中的程式碼
<form action="" method="post" enctype="multipart/form-data">
<input type="text" name="title"><br>
<input type="text" name="content"><br>
{# <input type="file" name="myfile"><br>#}
<input type="file" name="file"><br>
<input type="submit" value="提交"><br>
</form>
這樣,就完成了我們的程式碼,就可以輸入網址進行測試效果了。
上傳圖片:
上傳圖片跟上傳普通檔案是一樣的。只不過是上傳圖片的時候Django會判斷上傳的檔案是否是圖片的格式(除了判斷後綴名,還會判斷是否是可用的圖片)。如果不是,那麼就會驗證失敗。
這裡我們就修改models中的欄位就行了,就不去新增新的欄位了。
models中修改程式碼:
class Article(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
# 只允許上傳txt檔案
# file = models.FileField(upload_to='%Y/%m/%d/',validators=[validators.FileExtensionValidator(['txt'],message='file必須為txt檔案')])
# 上傳圖片
file = models.ImageField(upload_to='%Y/%m/%d/')
forms中修改程式碼:
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = '__all__'
error_messages = {
'cover':{
'invalid_image':'請上傳正確格式的圖片~~',
},
}
然後就能對圖片進行上傳了,ImageField欄位在底層會幫我們進行驗證是否為可用的圖片,如果不是,就會返回錯誤。
注意: 使用ImageField,必須要先安裝Pillow庫:pip install pillow,如果安裝了pillow庫,仍然有錯誤的話,應該就是pillow庫版本過低,可以安裝指定的最新版本:
目前我的最新版本為5.3.0。可以輸入以下命令安裝
pip install pillow==5.3.0