前端上傳文件的幾種方法


1.上傳文件按鈕定制

  一般文件上傳的按鈕都比較丑,我們可以通過下面的代碼實現按鈕樣式的更換

views.py

def upload_file(request):
    if request.method=="GET":
        return render(request,'upload_file.html')
    user = request.POST.get("user")
    pwd = request.POST.get("pwd")
    # 文件名
    avator = request.FILES.get("customer_file")
    with open(avator.name,'wb') as f:
        for line in avator:
            f.write(line)
    return HttpResponse('上傳成功')
上傳文件

upload_file.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form method="post" enctype="multipart/form-data">
        {% csrf_token %}
       <div style="position: relative;display: inline-block;height: 50px;min-width: 300px;overflow: hidden;">
            <div style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;z-index: 1000;border: 1px dotted #9d9d9d;color: #9d9d9d;line-height: 50px;padding-left: 15px;">
                <span>點擊上傳文件</span>
            </div>
            <input name="customer_file" type="file" id="excelFile"
                   style="position: absolute;top: 0;left: 0;right: 0;bottom: 0;background-color: #333333;z-index: 1001;opacity: 0;filter:alpha(opacity=0);">
        </div>
        <div>
            <input type="text" name="user">
            <input type="submit" value="提交">
        </div>
    </form>
    <script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
    $(function () {
        $('#excelFile').change(function (e) {
            // e.target得到的是input標簽,e.target.files得到是一串filelist,
            // e.target.files[0]得到的是圖片的一些參數,這些參數可以根據自己的需要提取
            var fileName = e.target.files[0].name;
            $(this).prev().find('span').text(fileName);
        })
    })
</script>
</body>
</html>
View Code

# form表單的enctype設置為multipart/form-data后,表單中除了文件后台能拿到,其他值后台都拿不到。

1.1針對excel表格文件上傳讀取到數據庫

models.py

class Excles(models.Model):
    user = models.CharField(max_length=36)
    age = models.IntegerField()
    email = models.EmailField()
    firm = models.CharField(max_length=36)
View Code

url.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('upload/', views.upload),
    path('index/', views.index),
]
View Code

views.py

from django.shortcuts import render
from app01.models import Excles

def index(request):
    return render(request,'index.html')

import xlrd
import os
def upload(request):
    if request.method == "GET":
        return render(request,'upload.html')
    avatar = request.FILES.get('customer_excel')
    print(type(avatar),avatar)   # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> test.xlsx
    print(type(avatar.name),avatar.name)    # <class 'str'> test.xlsx

    # 寫入文件
    with open(avatar.name, 'wb') as f:
        for line in avatar:
            f.write(line)
    files = xlrd.open_workbook(avatar.name)
    sheet = files.sheet_by_index(0)     # 選取sheet1表格
    row = sheet.nrows  # 列表行數
    mes_lis = []
    for i in range(1,row):
        rows = sheet.row_values(i)  # 每行數據
        rows_lis = Excles(user=rows[0], age=rows[1],email=rows[2],firm=rows[3])
        mes_lis.append(rows_lis)
    # bulk_create只能接收列表,用於批量寫入數據
    Excles.objects.bulk_create(mes_lis)
    os.remove(avatar.name)  # 移除這個表格
    info = Excles.objects.all()
    return render(request,'index.html',{'info':info})
View Code

upload.html

from django.shortcuts import render
from app01.models import Excles

def index(request):
    return render(request,'index.html')

import xlrd
import os
def upload(request):
    if request.method == "GET":
        return render(request,'upload.html')
    avatar = request.FILES.get('customer_excel')
    print(type(avatar),avatar)   # <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> test.xlsx
    print(type(avatar.name),avatar.name)    # <class 'str'> test.xlsx

    # 寫入文件
    with open(avatar.name, 'wb') as f:
        for line in avatar:
            f.write(line)
    files = xlrd.open_workbook(avatar.name)
    sheet = files.sheet_by_index(0)     # 選取sheet1表格
    row = sheet.nrows  # 列表行數
    mes_lis = []
    for i in range(1,row):
        rows = sheet.row_values(i)  # 每行數據
        rows_lis = Excles(user=rows[0], age=rows[1],email=rows[2],firm=rows[3])
        mes_lis.append(rows_lis)
    # bulk_create只能接收列表,用於批量寫入數據
    Excles.objects.bulk_create(mes_lis)
    os.remove(avatar.name)  # 移除這個表格
    info = Excles.objects.all()
    return render(request,'index.html',{'info':info})
View Code

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<link href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet">
<body>
     <div class="container">
       <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
       <table class="table table-hover">
        <thead>
            <tr>
                <th>序號</th>
                <th>用戶名</th>
                <th>年齡</th>
                <th>郵箱</th>
                <th>公司</th>
            </tr>
        </thead>
           <tbody>
            {% for ret in info %}
                <tr>
                <td>{{ ret.pk }}</td>
                <td>{{ ret.user }}</td>
                <td>{{ ret.age }}</td>
                <td>{{ ret.email }}</td>
                <td>{{ ret.firm }}</td>
                </tr>
            {% endfor %}

       </table>
       </div>
   </div>
</body>
</html>
View Code

這個例子很簡單,其中需要注意的幾個點:

針對文件上傳的視圖函數中參數進行補充說明

avatar.name:這是一個屬性,不是方法,該屬性得到上傳的文件名,包括后綴,如123.exe;

avatar.size:這也是一個屬性,該屬性得到上傳文件的大小

myFile.read():從文件中讀取整個上傳的數據,這個方法只適合小文件;

myFile.chunks():按塊返回文件,通過在for循環中進行迭代,可以將大文件按塊寫入到服務器中;

myFile.multiple_chunks():這個方法根據myFile的大小,返回True或者False,當myFile文件大於2.5M(默認為2.5M,可以調整)時,該方法返回True,否則返回False,因此可以根據該方法來選擇選用read方法讀取還是采用chunks方法:

針對bulk_create的使用說明

  該方法是在django1.4版本之后才有的,針對文本文件的批量導入

  create()每保存一條就執行一次SQL,而bulk_create()是執行一條SQL存入多條數據,會快很多

  詳細上傳文件的說明請參考該技術博客

2.上傳圖片(針對較新版本瀏覽器)

  上傳圖片和文件的區別主要在於圖片上傳上去,一方面要在前端顯現出來,一方面還要存儲在后端,而文件只是實現了單方面

案例:

默認圖片(存放在/static/img路徑下):

default.png

views.py

import os
import uuid   # 生成一串隨機數,用於給每個圖片起隨機名字
def upload_img(request):
    if request.method == "GET":
        return render(request,'upload_img.html')
    avatar = request.POST.get('avatar')
    # 圖片名
    print(avatar)
    return HttpResponse('上傳成功')

# 該函數是前端ajax來響應的
def form_data_upload(request):
    """
    ajax上傳文件
    :param request:
    :return:
    """
    img_upload = request.FILES.get('img_upload')
    # 圖片名
    print(">>>",img_upload)
    # 修改后的圖片名
    file_name = str(uuid.uuid4()) + "." + img_upload.name.rsplit('.', maxsplit=1)[1]
    # 圖片路徑,這里我創建了一個static文件,下面有創建了一個img文件,用於放置圖片
    img_file_path = os.path.join('static','img', file_name)
    with open(img_file_path, 'wb') as f:
        for line in img_upload.chunks():
            f.write(line)
    return HttpResponse(img_file_path)
View Code

模板一(createObjectURL):

upload_img.html

# URL.createObjectURL()方法會根據傳入的參數創建一個指向該參數對象的URL. 這個URL的生命僅存在於它被創建的這個文檔里. 新的對象URL指向執行的File對象或者是Blob對象。當不再需要這些 URL 對象時,每個對象必須通過調用 URL.revokeObjectURL() 方法來釋放

createObjectURL技術參考點擊此處

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
    {# 圖片存儲路徑#}
    <img style="height: 100%;width: 100%;border: 0;overflow: hidden;border-radius: 50%;"
         id="previewImg"
        {# 默認圖片 #}
         src="/static/img/default.png">
    <input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;" id="avatarImg"
           name="avatar_img" type="file" class="img-file"/>
</div>
<div>點擊圖片更換(<a href="#">撤銷</a>)</div>

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <div>
        <input type="text" name="avatar" id="avatar">

        <input type="submit" value="提交">
    </div>
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
 <script>
        $(function () {
            bindChangeAvatar1();
        });
        function bindChangeAvatar1() {
            $('#avatarImg').change(function () {
                var file_obj = $(this)[0].files[0];
                // File對象,就是一個文件,比如我用input type="file"標簽來上傳文件,那么里面的每個文件都是一個File對象.
                var blob = window.URL.createObjectURL(file_obj);
                console.log(blob);
                // Blob對象,就是二進制數據,比如通過new Blob()創建的對象就是Blob對象.又比如,在XMLHttpRequest里,
                // 如果指定responseType為blob,那么得到的返回值也是一個blob對象.
                // blob:http://127.0.0.1:8002/24b475b2-0de0-430b-a13d-e613ece37cd8
                document.getElementById('previewImg').src = blob;
                $('#previewImg').load(function () {
                    window.URL.revokeObjectURL(blob);
                })
            })
        }
    </script>
</body>
</html>
View Code

模板二(FileReader):

upload_img.html

# 使用FileReader對象的readAsDataURL方法可以將讀取到的文件編碼成Data URL。Data URL是一項特殊的技術,可以將資料(例如圖片)內嵌在網頁之中,不用放到外部文件。使用Data URL的好處是,您不需要額外再發出一個HTTP 請求到服務器端取得額外的資料,它適合應用在內嵌小圖片。

FileReader技術參考連接點擊此處

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
    {# 圖片存儲路徑#}
    <img style="height: 100%;width: 100%;border: 0;overflow: hidden;border-radius: 50%;"
         id="previewImg"
        {# 默認圖片 #}
         src="/static/img/default.png">
    <input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;" id="avatarImg"
           name="avatar_img" type="file" class="img-file"/>
</div>
<div>點擊圖片更換(<a href="#">撤銷</a>)</div>

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <div>
        <input type="text" name="avatar" id="avatar">

        <input type="submit" value="提交">
    </div>
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
  <script>
        $(function () {
            bindChangeAvatar2();
        });

        function bindChangeAvatar2() {
            $('#avatarImg').change(function () {
                var file_obj = $(this)[0].files[0];
                console.log(file_obj);
                // 獲取文件對象,當中的值以鍵值對的形式存儲
                // File(352418) {name: "django生命周期.png", lastModified: 1531814882442,
                // lastModifiedDate: Tue Jul 17 2018 16:08:02 GMT+0800 (中國標准時間),
                // webkitRelativePath: "", size: 352418, …}
                var reader = new FileReader();
                reader.readAsDataURL(file_obj);
                reader.onload = function (e) {
                    $('#previewImg')[0].src = this.result;
                };
            })
        }
    </script>
</body>
</html>
View Code

模板三(FormData,基於ajax實現文件上傳):

upload_img.html

  主流瀏覽器都開始支持一個叫做FormData的對象,有了這個FormData,可以實現利用ajax上傳文件,

  目前主流瀏覽器的較新版本都已經支持這個對象了,比如Chrome 7+、Firefox 4+、IE 10+、Opera 12+、Safari 5+

  技術參考鏈接點擊此處

  案例參考鏈接點擊此處

# 通過 FormData.append()方法賦給字段的值若是數字會被自動轉換為字符(字段的值可以是一個Blob對象,一個File對象,或者一個字符串,剩下其他類型的值都會被自動轉換成字符串).

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
    {# 圖片存儲路徑#}
    <img style="height: 100%;width: 100%;border: 0;overflow: hidden;border-radius: 50%;"
         id="previewImg"
        {# 默認圖片 #}
         src="/static/img/default.png">
    <input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;" id="avatarImg"
           name="avatar_img" type="file" class="img-file"/>
</div>
<div>點擊圖片更換(<a href="#">撤銷</a>)</div>

<form method="post" enctype="multipart/form-data">
    {% csrf_token %}
    <div>
        <input type="text" name="avatar" id="avatar">

        <input type="submit" value="提交">
    </div>
</form>
<script src="/static/js/jquery-3.2.1.min.js"></script>
    <script>
        $(function () {
            bindChangeAvatar3();
        });

        function bindChangeAvatar3() {
            $('#avatarImg').change(function () {
                var file_obj = $(this)[0].files[0];
                // 得到的是文件對象
                console.log(file_obj);
                // FormData的最大優點就是可以異步上傳一個二進制文件
                var form = new FormData();
                // FormData {}
                console.log(form);
                // 創建一個空的FormData對象,然后再用append方法逐個添加鍵值對
                form.append('img_upload', file_obj);
                $.ajax({
                    url: '/form_data_upload/',
                    type:'POST',
                    data: form,
                    processData: false,  // tell jQuery not to process the data
                    contentType: false,  // tell jQuery not to set contentType
                    success: function (arg) {
                        // arg,即后端發送過來的完整圖片路徑,
                        // static\img\53632381-9c69-4280-b8e6-e1dcc35df412.jpg
                        console.log(arg);
                        // 更換默認圖片
                        $('#previewImg').attr('src',"/"+arg);
                        // input框顯示圖片路徑
                        $('#avatar').val("/"+arg);
                    }
                })
            })
        }
    </script>
</body>
</html>
View Code

# 需要注意的是這里的模板響應了兩個視圖函數,一定要記得在url中配制好路徑

3.上傳圖片(對瀏覽器兼容廣泛)

views.py

USER_LIST = []
#通過index將列表中的數據渲染在主頁
def index(request):
    return render(request,'index.html',{'user_list':USER_LIST})

# 獲取前端傳來的用戶名,密碼,圖片名稱
def iframe_upload_img(request):
    if request.method == "GET":
        return render(request,'iframe_upload_img.html')
    user = request.POST.get('user')
    pwd = request.POST.get('pwd')
    avatar = request.POST.get('avatar')
    USER_LIST.append(
        {
            'user':user,
            'pwd':pwd,
            'avatar':avatar
        }
    )
    # 重定向到主頁
    return redirect('/index/')


import json
import uuid     # 獲取隨機字碼
def upload_iframe(request):
    ret = {'status':True,'data':None}
    try:
        avatar = request.FILES.get('avatar')
        print(avatar)
        file_name = str(uuid.uuid4()) + "." + avatar.name.rsplit('.', maxsplit=1)[1]
        img_file_path = os.path.join('static', 'img', file_name)
        with open(img_file_path, 'wb') as f:
            for line in avatar.chunks():
                f.write(line)
        ret['data'] = os.path.join("/",img_file_path)
    except Exception as e:
        ret['status'] = False
        ret['error'] = '上傳失敗'
    return HttpResponse(json.dumps(ret))
    # return JsonResponse(ret)
View Code

模板四(通過iframe偽異步上傳):

iframe_upload_img.thml

# 在不支持html5的前提下,ajax技術是無法實現文件的異步上傳,因為ajax本質上還是js寫的。js不能操作瀏覽器端的主機,不能操作硬盤上的文件,所以無法上傳文件,這里可以通過iframe內聯框架,來偽裝實現無頁面的跳轉的異步上傳

# i通過frame偽異步上傳,我們在上傳文件的頁面內聯一個框架作為表單提交后的頁面,同時把這個內聯框架隱藏起來,偽造異步上傳

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div style="height: 100px;width: 100px;padding: 2px;border: 1px solid #dddddd;position: relative;">
    {# 這里給了個iframe標簽,這個標簽放置路徑可以局部顯示這個路徑畫面    #}
    <iframe style="display: none;" id="ifr" name="fffff"></iframe>
    <form method="POST" action="/upload_iframe/" enctype="multipart/form-data" target="fffff">
        {% csrf_token %}
        {# 默認圖片 #}
        <img style="height: 100px;width: 100px;border: 0;overflow: hidden;border-radius: 50%;" id="prevImg"
             src="/static/img/default.png">

        <input style="top: 0;left: 0;right: 0;bottom: 0;opacity: 0;position: absolute;z-index: 102;"
               id="avatar"
               name="avatar" type="file" class="img-file"/>
    </form>
</div>

<form method="post" action="/iframe_upload_img/">
    {% csrf_token %}
    <input type="text" name="avatar" id="formAvatar" style="display: none">
    <input type="text" name="user" placeholder="請輸入用戶名">
    <input type="text" name="pwd" placeholder="請輸入密碼">
    <input type="submit" value="提交">
</form>

<script src="/static/js/jquery-3.2.1.min.js"></script>
<script>
    $(function () {
        bindChangeAvatar4();
    });

    function bindChangeAvatar4() {
        $('#avatar').change(function () {
            // 父級是form表單
            $(this).parent().submit();
            // contentWindow 兼容各個瀏覽器,可取得子窗口的 window 對象。
            $('#ifr')[0].onload = function () {
                // 通過這種方式向iframe頁面傳遞參數
                var iframeContents = $('#ifr')[0].contentWindow.document.body.innerText;
                iframeContents = JSON.parse(iframeContents);
                console.log(iframeContents);
                if (iframeContents.status) {
                    $('#prevImg').attr('src', iframeContents.data);
                    $('#formAvatar').val(iframeContents.data);
                }
            }

        })
    }

</script>
</body>
</html>
View Code

# 這里的模板對應兩個form表單,分別對應兩個視圖函數

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM