about

本篇博客主要演示了,使用Django完成对本地Excel表格的上传下载操作,当然,其他类型的文件也一样。

环境:win10 + django1.11 + xlrd

上传

一般的, 上传可以分为通过form表单提交和通过ajax提交两种。

form表单上传

来看示例:

前端重要代码。

<div>
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" name="f1">
<input type="text" name="user">
<input type="submit" value="提交">
</form>
</div>

一般的,在普通的form表单提交时,请求头中的CONTENT_TYPE: application/x-www-form-urlencoded,然后数据是以键值对的形式传输的,服务端从request.POST取值,这没问题,并且CONTENT_TYPE: application/x-www-form-urlencoded这种编码类型满足大多数情况,一切都挺好的。

而要说使用form表单上传文件,就不得不多说两句了。

起初,http 协议中没有上传文件方面的功能,直到 rfc1867 为 http 协议添加了这个功能。当然在 rfc1867 中限定 form标签的 method 必须为 POSTenctype = "multipart/form-data" 以及<input type = "file">

所以,当使用form表单上传文件的时候,请求头的content_typemultipart/form-data这种形式的,所以,我们需要在form标签添加enctype="multipart/form-data属性来进行标识。

如果你能打印上传文件的请求头,你会发现CONTENT_TYPE是这样的content_type:multipart/form-data; boundary=----WebKitFormBoundarylZZyJUkrgm6h34DU,那boundary=----WebKitFormBoundarylZZyJUkrgm6h34DU又是什么呢?

multipart/form-data 后面有boundary以及一串字符,这是分界符,后面的一堆字符串是随机生成的,目的是防止上传文件中出现分界符导致服务器无法正确识别文件起始位置。那分界符又有啥用呢?

对于上传文件的post请求,我们没有使用原有的 http 协议,所以 multipart/form-data 请求是基于 http 原有的请求方式 post 而来的,那么来说说这个全新的请求方式与 post 的区别:

  1. 请求头的不同,对于上传文件的请求,contentType = multipart/form-data是必须的,而 post 则不是,毕竟 post 又不是只上传文件~。
  2. 请求体不同,这里的不同也就是指前者(上传文件请求)在发送的每个字段内容之间必须要使用分界符来隔开,比如文件的内容和文本的内容就需要分隔开,不然服务器就没有办法正常的解析文件,而后者 post 当然就没有分界符直接以key:value的形式发送就可以了。

当然,其中的弯弯绕绕不是三言两语能解释的清楚的,我们先知道怎么用就行。

再来看views视图处理:

from django.shortcuts import render, redirect, HttpResponse
from django.db import transaction
def import_case(request, pk):
""" 导入Excel数据,pk是所属项目的pk """
if request.method == 'POST':
try:
with transaction.atomic(): # 事物
# project_pk = request.POST.get("project_pk") # 数据库使用字段
excel = request.FILES.get('file_obj')
book = xlrd.open_workbook(filename=None, file_contents=excel.read())
sheet = book.sheet_by_index(0)
title = sheet.row_values(0)
for row in range(1, sheet.nrows):
print(sheet.row_values(row)) # 这里取出来每行的数据,就可以写入到数据库了
return HttpResponse('OK')
except Exception as e:
print(e)
return render(request, 'import_case.html', {"project_pk": pk, "error": "上传文件类型有误,只支持 xls 和 xlsx 格式的 Excel文档"}) return render(request, 'import_case.html', {"project_pk": pk, "error": ""})

ajax上传文件

前端文件:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!-- ajax上传文件开始 -->
<div>
{% csrf_token %}
<input type="file" id="ajaxFile">
<button id="ajaxBtn">上传</button>
</div>
<!-- ajax上传文件结束 -->
</body>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
console.log($("[name='csrfmiddlewaretoken']").val());
$("#ajaxBtn").click(function () {
// 首先,实例化一个formdata对象
var formData = new FormData();
// 然后使用formdata的append来添加数据,即获取文件对象
// var file_obj = $("#ajaxFile")[0].files[0]; // 使用jQuery获取文件对象
var file_obj = document.getElementById('ajaxFile').files[0]; // 使用dom也行
formData.append('f1', file_obj );
// 处理csrftoken
formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
// 也可以将其他的数据,以键值对的形式,添加到formData中
formData.append('user','张开');
$.ajax({
url: "/upload/",
type: "POST",
data: formData,
processData:false, //
contentType:false,
success:function (dataMsg) {
console.log(dataMsg);
}
})
})
</script>
</html>

在 ajax 中 contentType 设置为 false 是为了避免 JQuery 对请求头content_type进行操作,从而失去分界符,而使服务器不能正常解析文件。

在使用jQuery的$.ajax()方法的时候参数processData默认为true(该方法为jQuery独有的),默认情况下会将发送的数据序列化以适应默认的内容类型application/x-www-form-urlencoded

如果想发送不想转换的信息的时候需要手动将其设置为false即可。

再来看后端views.py如何处理:

import xlrd
from django.shortcuts import render
from django.http import JsonResponse def upload(request):
if request.is_ajax():
# print(request.META['CONTENT_TYPE']) # multipart/form-data; boundary=----WebKitFormBoundaryuXDgAwSKKIGnITam
# print(request.POST) # <QueryDict: {'csrfmiddlewaretoken': ['mx1EBTtsOb0k96TUUW8XKbCGvK0Co3S6ZMlLvOuZOKAlO9nfhf6zol0V8KxRxbwT'], 'user': ['张开']}>
# print(request.FILES) # <MultiValueDict: {'f1': [<InMemoryUploadedFile: 接口测试示例.xlsx (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)>]}>
f1 = request.FILES.get('f1')
print(f1) # 接口测试示例.xlsx
book = xlrd.open_workbook(filename=None, file_contents=f1.read())
sheet = book.sheet_by_index(0)
print(sheet.row_values(1)) # ['cnodejs项目', 'get /topics 主题首页', 'https://cnodejs.org/api/v1/topics', 'get', '', '{"success":true}']
return JsonResponse({"message": "upload successful"})
else:
return render(request, 'upload.html')

OK了,多说无益,干就完了。

下载

使用StreamingHttpResponse

views中主要代码:

from django.http import StreamingHttpResponse
def download(request):
file=open('crm/models.py','rb')
response =StreamingHttpResponse(file)
response['Content-Type']='application/octet-stream'
response['Content-Disposition']='attachment;filename="models.py"'
return response

使用FileResponse

views中主要代码:

from django.http import FileResponse
def download(request):
file=open('crm/models.py','rb')
response =FileResponse(file)
response['Content-Type']='application/octet-stream'
response['Content-Disposition']='attachment;filename="models.py"'
return response

解决filename不能有中文的问题

如果你细心的尝试,会发现,上面两中下载方式中的filename不能包含中文,那么如何解决呢?来,往下看!

from django.http import FileResponse
from django.utils.encoding import escape_uri_path # 导入这个家伙
def download(request):
file=open('crm/models.py','rb')
response =FileResponse(file)
response['Content-Type']='application/octet-stream'
response['Content-Disposition']='attachment;filename="{}.py"'.format(escape_uri_path("我是中文啦"))
return response

是不是解决了!完美!!


欢迎斧正,that's all
see also:[Django上传并读取Excel
](https://www.jianshu.com/p/88f1acea37f1) | [浅谈contentType = false](https://segmentfault.com/a/1190000007207128) | [$.AJAX()方法中的PROCESSDATA参数](https://www.cnblogs.com/zpsylgdx/p/10568837.html) | [详解django三种文件下载方式](https://www.jb51.net/article/137790.htm) | [Django实现下载文件](https://blog.csdn.net/sinat_38068807/article/details/96183220)

Django - 读取Excel文件的更多相关文章

  1. C# 读取EXCEL文件的三种经典方法

    1.方法一:采用OleDB读取EXCEL文件: 把EXCEL文件当做一个数据源来进行数据的读取操作,实例如下: public DataSet ExcelToDS(string Path) { stri ...

  2. c# .Net :Excel NPOI导入导出操作教程之读取Excel文件信息及输出

    c# .Net :Excel NPOI导入导出操作教程之读取Excel文件信息及输出 using NPOI.HSSF.UserModel;using NPOI.SS.UserModel;using S ...

  3. ADO.NET 读取Excel文件,并作数据源

    项目中需要用的功能,贴上代码了. 需要注意的地方:配置Web.config的时候要注意版本问题! //若是在Web.config中配置数据源,如下 <add key="ExcelCon ...

  4. PHPExcel读取Excel文件的实现代码

    <?php require_once 'PHPExcel.php'; /**对excel里的日期进行格式转化*/ function GetData($val){ $jd = GregorianT ...

  5. .Net读取Excel文件时丢失数据的问题 (转载)

    相信很多人都试过通过OleDB读取Excel文件,这种方法效率十分高,只是有一点会让人十分头痛,就是当一列中既有混合型数据,又有纯数据时,往往容易丢失数据. 百度过后,改连接字符串 “HDR=YES; ...

  6. 使用jxl,poi读取excel文件

    作用:在java后台添加一个方法,读取导入的excel内容,根据需要返回相应的sql语句,以完成对临时表的插入操作. 使用jxl读取excel文件 package com.sixthf.bi.sapp ...

  7. C# 读取Excel文件里面的内容到DataSet

    摘要:读取Excel文件里面的内容到DataSet 代码: /// <summary> /// 读取Excel文件里面的内容到DataSet /// </summary> // ...

  8. R语言读取excel文件的3种方法

    R读取excel文件中数据的方法: 电脑有一个excel文件,原始的文件路径是:E:\R workshop\mydata\biom excel数据为5乘2阶矩阵,元素为                ...

  9. C#读取Excel文件:通过OleDb连接,把excel文件作为数据源来读取

    转载于:http://developer.51cto.com/art/200908/142392.htm C#读取Excel文件可以通过直接读取和OleDb连接,把excel文件作为数据源来读取:   ...

随机推荐

  1. 算法练习之杨辉三角,杨辉三角的第 k 行,买卖股票的最佳时机

    1. 杨辉三角 给定一个非负整数 numRows,生成杨辉三角的前 numRows 行. 在杨辉三角中,每个数是它左上方和右上方的数的和. 示例: 输入: 输出: [ [], [,], [,,], [ ...

  2. csp联考T1

    本题主要难点在于如何处理dist^2的问题 40分算法 n^2暴力就不必多嘴,直接枚举根节点DFS就行了. 70分算法 对于b=0的情况,我们可以考虑用换根法来计算根节点的变化对总权值带来的影响. 换 ...

  3. C++标准异常与自定义异常

    参见https://www.runoob.com/cplusplus/cpp-exceptions-handling.html C++ 标准的异常 C++ 提供了一系列标准的异常,定义在 中,我们可以 ...

  4. mac远程连接linux 服务器桌面by VNC

    为了远程使用Linux服务器,折腾了一个下午.最终看来还是用vnc最简单了. 实验室有两台强劲的Linux服务器用来做研究.之前我一直都是用ssh登到服务器上去码代码,反应速度很快,感觉很不错.但是因 ...

  5. 【LeetCode】三数之和【排序,固定一个数,然后双指针寻找另外两个数】

    给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组. 注意:答案中不可以包含重复的三元组. ...

  6. JAVAWEB实现增删查改(图书信息管理)之添加功能实现

    addBooks.jsp页面代码:↓ <%-- Created by IntelliJ IDEA. User: NFS Date: 2019-7-12 Time: 14:30 To change ...

  7. Java开发笔记(一百一十八)AWT按钮

    前面介绍了如何通过AWT显示程序的窗口界面,那么要怎样在该窗口上面添加丰富多样的控件呢?注意Frame类是个窗口工具,它由窗楣(标题栏)与窗体(窗口主界面)两部分组成,故而Frame类只对整个窗口统筹 ...

  8. char * const * (*a) (int b)

    char * const * (*a) (int b), 按照c++ program language的读法,从右往左读,* 读作pointer to 把(*a) (int b看作整体, (*a) ( ...

  9. python基础_MySQL的bigint类型

    bigint支持的数字的大小范围为:19位,存电话号码.有符号范围:-9223372036854775808 到 9223372036854775807 int支持的数字范围为:10位,有符号范围:- ...

  10. [高清] Excel函数速记手册

    ------ 郑重声明 --------- 资源来自网络,纯粹共享交流, 如果喜欢,请您务必支持正版!! --------------------------------------------- 下 ...