Django用戶頭像上傳

1 將文件保存到服務器本地

upload.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!DOCTYPE html>
<html lang = "en" >
<head>
     <meta charset = "UTF-8" >
 
< / head>
<body>
 
<form action = " " method=" post " enctype=" multipart / form - data">
     { % csrf_token % }
     <div>用戶名:< input type = "text" name = "username" >< / div>
     <div>頭像< input type = "file" name = "avatar" >< / div>
     < input type = "submit" value = "提交" >
< / form>
 
< / body>
< / html>

urls.py

?
1
2
3
4
5
6
from django.conf.urls import url
from app01 import views
 
urlpatterns = [
     url(r '^upload' ,views.upload)
]

views.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
from django.shortcuts import render,HttpResponse
 
def upload(request):
     if request.method = = 'POST' :
         name = request.POST.get( 'username' )
         avatar = request.FILES.get( 'avatar' )
 
         with open (avatar.name, 'wb' ) as f:
             for line in avatar:
                 f.write(line)
         return HttpResponse( 'ok' )
 
     return render(request, 'upload.html' )

總結

這樣,咱們就作好了一個基本的文件上傳小示例,這裏須要注意的有幾點:html

  1. form表單裏須要加上csrf_token驗證
  2. 文件的input框的type的值爲file
  3. 在視圖函數中獲取文件要用request.FILES.get()方法
  4. 經過obj.name能夠獲取文件的名字

2 將文件上傳到數據庫

models.py

?
1
2
3
4
5
6
from django.db import models
 
 
class User(models.Model):
     username = models.CharField(max_length = 16 )
     avatar = models.FileField(upload_to = 'avatar' )

views.py

?
1
2
3
4
5
6
7
8
9
def upload(request):
     if request.method = = 'POST' :
         name = request.POST.get( 'username' )
         avatar = request.FILES.get( 'avatar' )
 
         models.User.objects.create(username = name,avatar = avatar)
         return HttpResponse( 'ok' )
 
     return render(request, 'upload.html' )

總結

上面已經實現了將文件上傳到數據庫的功能,須要注意的有幾點:python

  1. 所謂的上傳到數據庫,不是講圖片自己或者二進制碼放在數據庫,實際上也是將文件上傳到服務器本地,數據庫只是存了一個文件的路徑,這樣用戶要調用文件的時候就能夠經過路徑去服務器指定的位置找了
  2. 建立ORM的時候,avatar字段要有一個upload_to=''的屬性,指定上傳後的文件放在哪裏
  3. 往數據庫添加的時候,文件字段屬性賦值跟普通字段在形式上是同樣的,如:models.User.objects.create(username=name,avatar=avatar)
  4. 若是有兩個用戶上傳的文件名重複,系統會自動將文件更名,效果以下:

附加

功能咱們是實現了,看起來咱們在調用文件的時候,只須要經過數據庫文件路徑已經保存的文件自己就能夠訪問圖片,讓它出如今網頁上,其實並非這樣,jquery

咱們須要配置一些東西,django才能夠找的到,否則的話就會過不了urls驗證,而咱們之因此能夠直接訪問static裏的靜態文件,是由於django已經幫咱們配置好了。ajax

 

配置步驟以下:數據庫

一、在站點的setting.py裏配置django

?
1
2
MEDIA_ROOT = os.path.join(BASE_DIR, "blog" , "media" #blog是項目名,media是約定成俗的文件夾名
MEDIA_URL = "/media/"      # 跟STATIC_URL相似,指定用戶能夠經過這個路徑找到文件

二、在urls.py裏配置瀏覽器

?
1
2
3
4
from django.views.static import serve
from upload import settings                #upload是站點名
 
url(r '^media/(?P<path>.*)$' , serve, { 'document_root' : settings.MEDIA_ROOT}),
配置完後,就能夠經過http://127.0.0.1:8001/media/milk.png訪問到圖片了

 

 3 用AJAX提交文件

upload.html

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html lang = "en" >
<head>
     <meta charset = "UTF-8" >
< / head>
<body>
 
<form>
     { % csrf_token % }
     <div>用戶名:< input id = "name-input" type = "text" >< / div>
     <div>頭像< input id = "avatar-input" type = "file" >< / div>
     < input id = "submit-btn" type = "button" value = "提交" >
< / form>
 
<script src = "/static/js/jquery-3.2.1.min.js" >< / script>
<script>
     $( '#submit-btn' ).on( 'click' ,function () {
         formdata = new FormData();
         formdata.append( 'username' ,$( '#name-input' ).val());<br><br>        formdata.append( "avatar" ,$( "#avatar" )[ 0 ].files[ 0 ]);
?
1
formdata.append( "csrfmiddlewaretoken" ,$( "[name='csrfmiddlewaretoken']" ).val()); <br>    $.ajax({<br>         processData:false,<br>         contentType:false, <br>         url: '/upload' , <br>         type : 'post' , <br>         data:formdata, <br>         success:function (arg) { <br>           if (arg.state = = 1 ){ alert( '成功!' ) } else { alert( '失敗!' ) } } }) });<br> < / script> < / body> < / html>

views.py

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from app01 import models
 
def upload(request):
     if request.method = = 'POST' :
         name = request.POST.get( 'username' )
         avatar = request.FILES.get( 'avatar' )
 
         try :
             models.User.objects.create(username = name,avatar = avatar)
             data = { 'state' : 1 }
         except :
             data = { 'state' : 0 }
 
         return JsonResponse(data)
 
     return render(request, 'upload.html' )

總結

  1. Ajax上傳的時候,按鈕的tpye必定不要用submit
  2. Ajax上傳的時候data參數的值再也不是一個普通‘字典’類型的值,而是一個FormData對像
    • 建立對象formdata = new FormData();
    • 往裏面添加值formdata.append('username',$('#name-input').val());
  3. Ajax在作post提交的時候要加上csrf驗證
    • formdata.append("csrfmiddlewaretoken",$("[name='csrfmiddlewaretoken']").val());
  4. 最後,Ajax上傳文件的時候要有兩個參數設置
    • processData:false
    • contentType:false

4 上傳圖片文件的時候有預覽功能

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang = "en" >
<head>
     <meta charset = "UTF-8" >
< / head>
<body>
 
<form>
     <! - - - - 用一個label標籤將上傳文件輸入框跟圖片綁定一塊兒,
           點擊圖片的時候就至關於點擊了上傳文件的按鈕 - - - - >
     <label><img id = "avatar-img" src = "/static/img/default.png" width = "80px" height = "80px" >
         <div>頭像< input id = "avatar-input" hidden type = "file" >< / div>
     < / label>
 
     < input id = "submit-btn" type = "button" value = "提交" >
< / form>
 
<script src = "/static/js/jquery-3.2.1.min.js" >< / script>
 
<script>
 
     / / 上傳文件按鈕(label裏的圖片)點擊事件
     $( '#avatar-input' ).on( 'change' ,function () {
         / / 獲取用戶最後一次選擇的圖片
         var choose_file = $(this)[ 0 ].files[ 0 ];
         / / 建立一個新的FileReader對象,用來讀取文件信息
         var reader = new FileReader();
         / / 讀取用戶上傳的圖片的路徑
         reader.readAsDataURL(choose_file);
         / / 讀取完畢以後,將圖片的src屬性修改爲用戶上傳的圖片的本地路徑
         reader.onload = function () {
              $( "#avatar-img" ).attr( "src" ,reader.result)
         }
     });
 
< / script>

 5 大總結

對於文件上傳,無論是直接form提交也好,Ajax提交也好,根本問題是要告訴瀏覽器你要上傳的是一個文件而不是普通的字符串服務器

而怎麼樣告訴瀏覽器呢,就是經過請求體重的ContentType參數,咱們上傳普通的字符串的時候不用指定,由於它有默認值,app

而若是要傳文件的話,就要另外指定了。總結如下幾點函數

  1. form表單上傳的話是經過 enctype="multipart/form-data" 來指定ContentType
  2. ajax上傳的話是經過  processData:false 和 contentType:false來指定ContentType
  3. form上傳的時候,文件數據是經過<input type="file">標籤來‘’包裹‘’數據,
  4. ajax上傳的時候,是經過一個 FormData 實例對象來添加數據,傳遞的時候傳遞這個對象就好了
  5. 數據傳遞過去以後,是封裝在request.FILES裏而不是request.POST裏
相關文章
相關標籤/搜索