那些年,我們在Django web開發中踩過的坑(一)——神奇的‘/’與ajax+iframe上傳

來源:互聯網
上載者:User

標籤:

一、上傳圖片並在前端展示

為了避免前端整體重新整理,我們採用ajax+iframe(相容所有瀏覽器)上傳,這樣使用者上傳之後就可以立即看到圖片:

上傳前:

上傳後:

前端部分html:

<form style="display: inline-block" id="upload_img_form" name="form" action="/upload/" method="POST"          enctype="multipart/form-data">        {% csrf_token %}          <a id="fakeFile" class="fake-file">            <input type="file" name="img" onchange="UploadImage(this);"/>            <input type="text" name="url" class="hide"/>        </a>        <iframe id=‘upload_img_iframe‘ name=‘upload_img_iframe‘ src="" class="hide"></iframe>    </form>

  別看這麼短短的html,坑卻不少:

  • 坑one:action="/upload/",當年筆者傻傻的就唯寫了action="/upload",因為url是這麼配的:url(r‘^upload‘, v.upload),結果

    django居然報錯了,筆者查了很多資料,最後才知道,原來,雖然url的最後沒有加‘/‘,但是django在運行時會自動給url的後面加‘/‘,因此,我們在post提交時,必須在url的最後加‘/‘。

  • 坑two:enctype="multipart/form-data",檔案上傳相對於其他表單類型出現的機率比較小,而檔案上傳確是這些表單類型中的異類,它需要在form寫上enctype="multipart/form-data"。
  • 坑three:{% csrf_token %},django運行程式時,請求首先會通過中介軟體,然後才會通過url,django設定檔中有關於跨站請求偽造的中介軟體:
    MIDDLEWARE_CLASSES = [    ‘django.middleware.security.SecurityMiddleware‘,    ‘django.contrib.sessions.middleware.SessionMiddleware‘,    ‘django.middleware.common.CommonMiddleware‘,    ‘django.middleware.csrf.CsrfViewMiddleware‘,    ‘django.contrib.auth.middleware.AuthenticationMiddleware‘,    ‘django.contrib.auth.middleware.SessionAuthenticationMiddleware‘,    ‘django.contrib.messages.middleware.MessageMiddleware‘,    ‘django.middleware.clickjacking.XFrameOptionsMiddleware‘,]

      django為使用者實現防止跨站請求偽造的功能,通過中介軟體 django.middleware.csrf.CsrfViewMiddleware 來完成。而對於django中設定防跨站請求偽造功能有分為全域和局部。

    全域:

      中介軟體 django.middleware.csrf.CsrfViewMiddleware

    局部:

    • @csrf_protect,為當前函數強制設定防跨站請求偽造功能,即便settings中沒有設定全域中介軟體。
    • @csrf_exempt,取消當前函數防跨站請求偽造功能,即便settings中設定了全域中介軟體。

    中介軟體‘django.middleware.csrf.CsrfViewMiddleware‘,會查看post請求是否攜帶token ,如果沒有則直接在process_request中return 並報出如下錯誤:

    此時,我們有幾種處理方式:1.直接簡單粗暴的注釋掉settings中的csrf中介軟體;2.給接收post請求的views函數加@csrf_exempt(註:from django.views.decorators.csrf import csrf_exempt,csrf_protect),該裝飾器的意思是取消當前函數防跨站請求偽造功能;

JavaScript代碼: 

function UploadImage(ths) {        document.getElementById(‘upload_img_iframe‘).onload = UploadImageComplete;  //頁面載入完成後執行UploadImageComplete函數        document.getElementById(‘upload_img_form‘).target = ‘upload_img_iframe‘;  //設定form提交到iframe        document.getElementById(‘upload_img_form‘).submit(); //#提交到iframe    }    function UploadImageComplete() {        var origin = $("#upload_img_iframe").contents().find("body").text();//#擷取圖片資料        var obj = JSON.parse(origin); //#轉換成JavaScript對象            var img = document.createElement(‘img‘); //#建立img標籤            img.src = obj.path; //圖片地址            img.style.width = "200px";            img.style.height = "180px";            $("#upload_img_form").append(img);//添加圖片            $(‘#fakeFile‘).addClass(‘hide‘);            $(‘#reUploadImage‘).removeClass(‘hide‘);            $(‘#fakeFile‘).find(‘input[type="text"]‘).val(obj.data);//#儲存圖片地址到隱藏的input標籤中    }

  後台views函數代碼:

def upload(request):    if request.method == ‘POST‘:        obj = request.FILES.get(‘img‘)#擷取圖片對象        pat = os.path.join(‘static‘,‘img‘,‘vote‘,obj.name)#檔案開啟目錄,需要和當前檔案路徑一致             f = open(pat,‘wb‘)        for ch in obj.chunks():            f.write(ch)        f.close()        ret = {‘path‘: ‘/‘+os.path.join(‘static‘,‘img‘,‘vote‘,obj.name)}#django前端檔案路徑:‘/‘ + 靜態檔案首碼static + 靜態檔案下的目錄        import json        return HttpResponse(json.dumps(ret))#反饋給前端    return render(request,‘upload.html‘,)

後台和前端js關於檔案路徑再現一坑:

  註:這裡我們將圖片儲存在靜態檔案目錄static下的img中(靜態檔案路徑的首碼也是static)

  django前端我們希望的引入圖片的路徑是這樣的:/static/img/xx.png,這裡需要注意的是static前必須加‘/‘,沒錯,就是這個神奇的‘/‘,代表當前程式主目錄,即設定檔中的BASE_DIR。

  後台我們開啟檔案寫入圖片到伺服器的路徑,這裡open路徑需要遵循的是python的規則而不是django前端的規則,即python會預設從當前路徑開始找,因此直接static/img/xx.png就行,前面不需要加‘/‘。

二、資料庫查詢結果給前端反饋序列化的問題

  

 

  json不能序列化django中的datatime、Decimal等資料結構,解決方案:

1.單獨轉為python資料結構

str( Decimal(‘12.36‘))

  然後通過json進行序列化。

2.直接將資料庫查詢結果QuerySet對象轉化為列表,QuerySet看起來像列表

ret=list(QuerySet對象)
result=json.dumps(ret)

  由於json.dumps時無法處理datetime日期,所以可以通過自訂處理器來做擴充,如:

import json from datetime import date from datetime import datetime    class JsonCustomEncoder(json.JSONEncoder):         def default(self, field):              if isinstance(field, datetime):             return o.strftime(‘%Y-%m-%d %H:%M:%S‘)         elif isinstance(field, date):             return o.strftime(‘%Y-%m-%d‘)         else:             return json.JSONEncoder.default(self, field)       # ds = json.dumps(d, cls=JsonCustomEncoder) 

  這是通過制定json.dumps序列化的類來實現的。

3.使用django的序列化工具serializers

from django.core import serializers ret = models.BookType.objects.all() data = serializers.serialize("json", ret)

  

 

  

   

那些年,我們在Django web開發中踩過的坑(一)——神奇的‘/’與ajax+iframe上傳

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.