目錄
1. 利用form表單上傳檔案
2. ajax上傳檔案
3. 上傳頭像時預覽頭像
4. 頭像存儲至資料庫
頭像存儲的路徑
通路上傳的圖檔
models.py中avatar字段方法
urls.py加入
url(r'^fileput/', views.fileput),
1. 利用form表單上傳檔案
模版檔案fileput.html:
{# 傳檔案必須用form-data這種類型#}
<form action="/fileput/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p><input type="text" name="username"></p>
<p><input type="file" name="myfile"></p>
<input type="submit">
</form>
注意:form标簽預設enctype="application/x-www-form-urlencoded",而上傳檔案時,必須設定enctype="multipart/form-data",否則服務端取不到檔案對象。input标簽的type='file'
視圖檔案views.py
def fileput(req):
if request.method == 'POST':
print(request.POST) #<QueryDict: {'username': ['caigy'], 'csrfmiddlewaretoken': ['kUK5RON4eMj3PPeIYTvW7XtqOAzrKDiIXVfI93zizMPJ6kQQOku4PHch3uSGRnfK']}>
print(request.FILES) #檔案對象 <MultiValueDict: {'myfile': [<InMemoryUploadedFile: meinv.jpg (image/jpeg)>]}>
file_obj = request.FILES.get('myfile')
print(file_obj.name) # 列印檔案名
with open(file_obj.name,'wb') as f: #預設寫在項目根目錄下
for line in file_obj:
f.write(line)
return render(req,'fileput.html')
注意: request.FILES是一個字典類型的資料,key是前端input标簽的name值,值就是前端上傳的檔案對象。
//擷取檔案對象
file_obj = request.FILES.get('myfile')
file_name = file_obj.name
//擷取檔案名稱
檔案是以二進制的方式傳遞到後端的,是以将上傳的檔案寫入到服務端本地時,直接用wb模式
2. ajax上傳檔案
模版檔案fileput.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{# 傳檔案必須用form-data這種類型#}
<form action="/fileput/" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p><input type="text" name="username"></p>
<p><input type="file" name="myfile"></p>
{# <input type="submit">#}
</form>
<button>sendAjax</button>
<script src="/static/dist/js/jquery-3.2.1.js"></script>
<script>
$('button').click(function () {
var formdata = new FormData(); //JS文法,執行個體化出來的對象是一個類似python字典一樣的容器,可以傳大檔案;
formdata.append('username',$('[name="username"]').val());
formdata.append('imgFile',$('[name="myfile"]')[0].files[0]);
formdata.append('csrfmiddlewaretoken',$('[name="csrfmiddlewaretoken"]').val());
$.ajax('/fileput/',{
type:'post',
processData:false, //不做預處理,預設為true
contentType:false, //關閉預設資料類型,預設值為x-www-form-urlencoded
data: formdata,
success:function (data) {
console.log(data)
}
})
})
</script>
</body>
</html>
注意:特别注意:利用ajax上傳檔案時,必須将processData設定為false,contentType設定為false。也就是不對資料做預處理。否則前端jquery會報錯。
是JS文法,執行個體化出來的對象是一個類似python字典一樣的容器,可以傳大檔案;
var formdata = new FormData();
可以取到存儲在
$('[name="myfile"]')[0].files[0])
中的檔案對象,檔案對象中包含以下圖中的内容:
<input type="file" name="myfile">
檔案對象中包含的内容![]()
第22天,檔案上傳 - processData預設值是true,contentType預設值是x-www-form-urlencoded,這個配置的意義是,當processData的值為true時,就将資料預處理成contentType設定的類型,contentType:"x-www-form-urlencoded"會将資料處理成這樣“?a=1&b=2”發送至後端,當沒有寫processData和contentType時,浏覽器預設processData為ture,contentType為'x-www-form-urlencoded'。
視圖檔案views.py:
def fileput(request):
if request.is_ajax(): #判斷是不是ajax請求
print(request.POST)
file_obj = request.FILES.get('imgFile')
imgpath = r'./blog/static/images/'
print(file_obj.name)
filepath = os.path.join(imgpath,file_obj.name)
with open(filepath,'wb') as f: #将上傳的檔案寫到指定路徑
for line in file_obj:
f.write(line)
return HttpResponse('上傳成功')
return render(request,'fileput.html')
3. 上傳頭像時預覽頭像
模版html檔案上傳頭像的部分代碼内容如下:
<!-- 頭像預覽部分的CSS樣式 -->
<style>
#avatar{
position: relative;
width: 60px;
height: 60px;
}
#avatar_img,#file{
width: 60px;
height: 60px;
position: absolute;
left: 20px;
top:0;
border: 1px solid white;
-webkit-border-radius: 8px;
-moz-border-radius: 8px;
border-radius: 8px;
}
#file{
opacity: 0;
}
</style>
<form class="form-horizontal" id="f1" novalidate method="post">
<div class="form-group has-feedback" >
<label for="id_password_confirm" class="col-md-2 control-label">頭像</label>
<div class="col-md-7" id="avatar">
<p><img src="/static/images/default.png" alt="" id="avatar_img"></p>
<p><input type="file" id="file"></p>
</div>
</div>
</form>
<script>
// 頭像預覽功能,就是将img标簽的src路徑換成要上傳的本地檔案路徑,此時還不會上傳至服務端。
$("#file").change(function () {
//必須用onchange事件,當标簽發生改變時觸發執行。
var choose_file=$("#file")[0].files[0];
var reader=new FileReader(); //檔案閱讀器對像
reader.readAsDataURL(choose_file); //可以讀出指定檔案的url路徑
reader.onload=function () {
$("#avatar_img").attr("src",this.result)
//this就是目前事件對象,this.result就是reader.result,擷取的值是choose_file檔案對象的url路徑
}
})
</script>
注意:頭像預覽功能原理時,點選上傳檔案後選擇了圖檔後,就将img标簽的src路徑換成被選擇的圖檔本地路徑,不能使用點選事件(onclick),應該使用onchange事件(jquery中是change事件),當标簽發生改變時才觸發。
4. 頭像存儲至資料庫
頭像存儲的路徑
models.py中的UserInfo類中的avatar字段設定:
class UserInfo(Form):
...
avatar = models.FileField(verbose_name='頭像', upload_to='avatar/', default="avatar/default.png")
...其他字段省略
資料庫中存儲頭像的字段avatar,實際存儲的是這個頭像檔案的相對路徑,是通過UserInfo表中avatar字段的upload_to參數的值+檔案名:即avatar/a.png。django會在項目根目錄下建立一個名為avatar的目錄,将檔案存至avatar目錄下。
當settings.py中配置了
# 使用者上傳的檔案路徑配置
MEDIA_URL = '/media/' # 是MEDIA_ROOT的别名
MEDIA_ROOT = os.path.join(BASE_DIR,'blog','media') #在blog應用下建立一個media目錄
django就會自動在MEDIA_ROOT目錄下建立一個avatar目錄,然後将檔案存至此目錄下,真實檔案存儲的絕對路徑:MEDIA_ROOT+upload_to+檔案名。假如項目名稱為myblog,那檔案存儲的真實路徑為:./myblog/blog/media/avatar/a.png
通路上傳的圖檔
假設使用者上傳了一個圖檔:a.jpg
如果settings.py中設定了MEDIA_URL="/media/",通路時應該寫的路徑為:/media/avatar/a.jpg
要想在前端頁面直接通路使用者上傳的檔案,還需要配置一條url,urls.py添加如下:
# 必須先導入如下子產品
from django.views.static import serve
from myblog import settings
urlpatterns = [
#... 省略部配置設定置 ...
# 添加media 配置
url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
]
前端上傳頭像後,後端視圖函數views.py存入資料庫:
def register(req):
form = RegistForm()
if req.method == 'POST':
response = {'status': True, 'msg': None, 'query': None}
form = RegistForm(req.POST)
if form.is_valid():
valid_code = form.cleaned_data['valid']
if valid_code.upper() == req.session['valid_code'].upper():
form.cleaned_data.pop('password_confirm')
form.cleaned_data.pop('valid') # 驗證碼和确認密碼不需要存入資料庫,是以需要從幹淨資料中去除掉。
avatar = req.FILES.get('avatar') # 從前端擷取上傳的檔案對象
form.cleaned_data['avatar'] = avatar
# 将檔案對象加入到幹淨資料中,以便寫入到資料庫中;\
# django會根據models.py中的UserInfo類下的avatar字段的upload_to參數設定的目錄名,建立一個目錄,\
# 然後把這個檔案對象存至這個目錄下,資料庫中存的是這個檔案的相對路徑
user = UserInfo.objects.create_user(**form.cleaned_data)
if user:
response['username'] = form.cleaned_data['username']
else:
response['status'] = False
response['query'] = '驗證碼錯誤'
else:
response['status'] = False
response['msg'] = form.errors
return HttpResponse(json.dumps(response))
return render(req,'register.html',locals())
models.py中avatar字段方法
user = UserInfo.objects.get(nid=1)
print('avatar_type:',user.avatar,type(user.avatar))
print('URL:',user.avatar.url)
print('PATH:',user.avatar.path)
print('NAME:',user.avatar.name)
print('SIZE:',user.avatar.size)
以上輸出的結果:
avatar_type: avatar/meinv.jpg <class 'django.db.models.fields.files.FieldFile'>
URL: /media/avatar/meinv.jpg
PATH: E:\python\python_study\day22\myblog\blog\media\avatar\meinv.jpg
NAME: avatar/meinv.jpg
SIZE: 5241