1.上传文件按钮定制

  一般文件上传的按钮都比较丑,我们可以通过下面的代码实现按钮样式的更换

views.py




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

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




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

<!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




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

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




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

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


View Code


views.py




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

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




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

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




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

<!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

前端上传大文件到nginx 前端上传文件流_json_15

views.py




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

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技术参考点击此处



前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

<!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技术参考连接点击此处




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

<!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对象,或者一个字符串,剩下其他类型的值都会被自动转换成字符串).




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

<!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




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

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伪异步上传,我们在上传文件的页面内联一个框架作为表单提交后的页面,同时把这个内联框架隐藏起来,伪造异步上传




前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx

前端上传大文件到nginx 前端上传文件流_前端上传大文件到nginx_02

<!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表单,分别对应两个视图函数