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. django:下拉框二级联动实现

    注意:只列举核心部分代码 前台模板: 第一级下拉菜单: <div class="col-sm-4"> <select data-placeholder=" ...

  2. 整理通常的SQL SERVER优化流程

    1.SQL脚本或存储过程,跟踪存储过程的执行时长和reads,不正常的情况下,表明语句.存储过程有优化空间,通常是未加索引,或者索引的字段升降序进行调用: A:脚本是否需要新增或复用现有索引: B:脚 ...

  3. LeetCode 556. 下一个更大元素 III(Next Greater Element III)

    556. 下一个更大元素 III 556. Next Greater Element III 题目描述 给定一个 32 位正整数 n,你需要找到最小的 32 位整数,其与 n 中存在的位数完全相同,并 ...

  4. LeetCode 32. 最长有效括号(Longest Valid Parentheses) 31

    32. 最长有效括号 32. Longest Valid Parentheses 题目描述 给定一个只包含 '(' 和 ')' 的字符串,找出最长的包含有效括号的子串的长度. 每日一算法2019/6/ ...

  5. springboot2.1.7整合swagger2.9.2

    什么是swagger? swagger是用于定义API文档的一个框架. 为什么要使用swagger? 当下项目开发时前后端是分离的,那么接口就成了前后端唯一的纽带.前端工程师如何知道哪个接口是干嘛的? ...

  6. 1.RabbitMQ工作模型与基本原理

        1.了解 MQ 的本质和 RabbitMQ 的特性: 2.掌握 RabbitMQ 的 Java API 编程和 Spring 集成 RabbitMQ 1. MQ 了解 1.1. 消息队列简介 ...

  7. Java开发笔记(一百三十三)Swing的菜单

    传统的桌面程序基本是对某种类型的文件进行加工,例如Window自带的记事本用来读写文本文件,自带的画图程序用来查看和修改位图文件.为了方便用户切换各种操作,这些程序在窗口顶端放了一排菜单栏,单击菜单栏 ...

  8. python3遇到的问题

    a bytes-like object is required,not str': 问题出在python3.5和Python2.7在套接字返回值解码上有区别:python bytes和str两种类型可 ...

  9. 【Linux】一步一步学Linux——初识Linux命令解析器(10)

    目录 00. 目录 01. Shell简介 02. Shell分类 03. 交互式shell和非交互式shell 04. 登录shell和非登录shell 05. Shell类型 06. 参考 00. ...

  10. 从docker中备份oracle和mongo数据

    从docker中导出Oracle数据 这里推荐先把脚本文件放到容器里面(这里没有) #!/bin/sh # 进入容器 # 本机备份位置 /root/oracleData/dist/temp # 当前日 ...