第22天,文件上傳

目錄

1. 利用form表單上傳文件
2. ajax上傳文件
3. 上傳頭像時預(yù)覽頭像
4. 頭像存儲至數(shù)據(jù)庫
    頭像存儲的路徑
    訪問上傳的圖片
    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標(biāo)簽?zāi)Jenctype="application/x-www-form-urlencoded",而上傳文件時,必須設(shè)定enctype="multipart/form-data",否則服務(wù)端取不到文件對象。input標(biāo)簽的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是一個字典類型的數(shù)據(jù),key是前端input標(biāo)簽的name值,值就是前端上傳的文件對象。

  • file_obj = request.FILES.get('myfile') //獲取文件對象
  • file_name = file_obj.name //獲取文件名稱
    文件是以二進制的方式傳遞到后端的,所以將上傳的文件寫入到服務(wù)端本地時,直接用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,    //不做預(yù)處理,默認為true
            contentType:false,    //關(guān)閉默認數(shù)據(jù)類型,默認值為x-www-form-urlencoded
            data: formdata,
            success:function (data) {
                console.log(data)
            }
        })
    })
</script>
</body>
</html>

注意:

  • var formdata = new FormData(); 是JS語法,實例化出來的對象是一個類似python字典一樣的容器,可以傳大文件;
  • $('[name="myfile"]')[0].files[0]) ?可以取到存儲在<input type="file" name="myfile">中的文件對象,文件對象中包含以下圖中的內(nèi)容:
    文件對象中包含的內(nèi)容
  • processData默認值是truecontentType默認值是x-www-form-urlencoded,這個配置的意義是,當(dāng)processData的值為true時,就將數(shù)據(jù)預(yù)處理成contentType設(shè)定的類型,contentType:"x-www-form-urlencoded"會將數(shù)據(jù)處理成這樣“?a=1&b=2”發(fā)送至后端,當(dāng)沒有寫processData和contentType時,瀏覽器默認processData為ture,contentType為'x-www-form-urlencoded'。

特別注意:利用ajax上傳文件時,必須將processData設(shè)置為falsecontentType設(shè)置為false。也就是不對數(shù)據(jù)做預(yù)處理。否則前端jquery會報錯。

視圖文件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. 上傳頭像時預(yù)覽頭像

模版html文件上傳頭像的部分代碼內(nèi)容如下:

<!-- 頭像預(yù)覽部分的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>
    // 頭像預(yù)覽功能,就是將img標(biāo)簽的src路徑換成要上傳的本地文件路徑,此時還不會上傳至服務(wù)端。
    $("#file").change(function () {
        //必須用onchange事件,當(dāng)標(biāo)簽發(fā)生改變時觸發(fā)執(zhí)行。
          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就是當(dāng)前事件對象,this.result就是reader.result,獲取的值是choose_file文件對象的url路徑
        }
    })
</script>

注意:頭像預(yù)覽功能原理時,點擊上傳文件后選擇了圖片后,就將img標(biāo)簽的src路徑換成被選擇的圖片本地路徑,不能使用點擊事件(onclick),應(yīng)該使用onchange事件(jquery中是change事件),當(dāng)標(biāo)簽發(fā)生改變時才觸發(fā)。

4. 頭像存儲至數(shù)據(jù)庫

頭像存儲的路徑

models.py中的UserInfo類中的avatar字段設(shè)置:

class UserInfo(Form):
    ...
    avatar = models.FileField(verbose_name='頭像', upload_to='avatar/', default="avatar/default.png")
    ...其他字段省略

數(shù)據(jù)庫中存儲頭像的字段avatar,實際存儲的是這個頭像文件的相對路徑,是通過UserInfo表中avatar字段的upload_to參數(shù)的值+文件名:即avatar/a.png。django會在項目根目錄下創(chuàng)建一個名為avatar的目錄,將文件存至avatar目錄下。

當(dāng)settings.py中配置了

# 用戶上傳的文件路徑配置
MEDIA_URL = '/media/'     # 是MEDIA_ROOT的別名
MEDIA_ROOT = os.path.join(BASE_DIR,'blog','media')    #在blog應(yīng)用下創(chuàng)建一個media目錄

django就會自動在MEDIA_ROOT目錄下創(chuàng)建一個avatar目錄,然后將文件存至此目錄下,真實文件存儲的絕對路徑:MEDIA_ROOT+upload_to+文件名。假如項目名稱為myblog,那文件存儲的真實路徑為:./myblog/blog/media/avatar/a.png

訪問上傳的圖片

假設(shè)用戶上傳了一個圖片:a.jpg
如果settings.py中設(shè)置了MEDIA_URL="/media/",訪問時應(yīng)該寫的路徑為:/media/avatar/a.jpg

要想在前端頁面直接訪問用戶上傳的文件,還需要配置一條url,urls.py添加如下:

# 必須先導(dǎo)入如下模塊
from django.views.static import serve
from myblog import settings
urlpatterns = [
    #... 省略部分配置 ...
    # 添加media 配置
    url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
]

前端上傳頭像后,后端視圖函數(shù)views.py存入數(shù)據(jù)庫:

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')       # 驗證碼和確認密碼不需要存入數(shù)據(jù)庫,所以需要從干凈數(shù)據(jù)中去除掉。
                avatar = req.FILES.get('avatar')     # 從前端獲取上傳的文件對象
                form.cleaned_data['avatar'] = avatar
                    # 將文件對象加入到干凈數(shù)據(jù)中,以便寫入到數(shù)據(jù)庫中;\
                    # django會根據(jù)models.py中的UserInfo類下的avatar字段的upload_to參數(shù)設(shè)定的目錄名,創(chuàng)建一個目錄,\
                    # 然后把這個文件對象存至這個目錄下,數(shù)據(jù)庫中存的是這個文件的相對路徑
                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)

以上輸出的結(jié)果:

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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • apache下的httpclient工具可大大簡化開發(fā)過程中的點對點通信,本人將以微信多媒體接口為例,展示http...
    劃破的天空閱讀 5,523評論 0 32
  • 本文包括:1、文件上傳概述2、利用 Commons-fileupload 組件實現(xiàn)文件上傳3、核心API——Dis...
    廖少少閱讀 12,743評論 5 91
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • 22年12月更新:個人網(wǎng)站關(guān)停,如果仍舊對舊教程有興趣參考 Github 的markdown內(nèi)容[https://...
    tangyefei閱讀 35,393評論 22 257
  • 我追求活得快樂, 并非活得豐盛, 只是不得已途經(jīng)。
    暖風(fēng)吹麥浪閱讀 162評論 0 0

友情鏈接更多精彩內(nèi)容