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. eclipse 查看文件在磁盘里的位置

  2. win运行canal

    1.mysql开启log_bin 用命令查看是否开启 SHOW VARIABLES LIKE 'log_bin'; OFF为未开启,ON为开启 Win环境的话找到my.ini,Linux环境的话找到m ...

  3. 谷歌浏览器调试swoole长连接方法

    谷歌浏览器调试swoole长连接方法network标签里面的ws 看frames  

  4. C++中的虚函数以及虚函数表

    一.虚函数的定义 被virtual关键字修饰的成员函数,目的是为了实现多态 ps: 关于多态[接口和实现分离,父类指针指向子类的实例,然后通过父类指针调用子类的成员函数,这样可以让父类指针拥有多种形态 ...

  5. template模板语言

    模板渲染 通过views视图函数对html页面进行渲染 标签{{ 变量 }}/标签 {% 逻辑 %} -- 标签 万能的点 <h1>91李业网</h1> <h2>{ ...

  6. python 之 Django框架(Django框架简介、视图装饰器、request对象、Response对象)

    12.33 Django框架简介: MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器( ...

  7. 关于TI公司DSP工程调用DELAY_US()进入非法中断问题的解决

    最近笔者在调试一个DSP程序时,发现在ad外设初始化时无法正常执行,单步检查,发现当执行到调用 DELAY_US(1000);语句时,就跳入非法. 进一步追查,DELAY_US()是宏定义函数,在笔者 ...

  8. 成员函数内定义static变量(不安全,各对象之间共享)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u012317833/article/de ...

  9. tsql获取sqlserver某个库下所有表

    ) declare my_cursor cursor for (select [name] from SysObjects where XType='U') open my_cursor fetch ...

  10. Windows服务创建及发布

    二.创建Windows Service 1.新建一个Windows Service,并将项目名称改为“MyWindowsService”,如下图所示: 2.在解决方案资源管理器内将Service1.c ...