【web】【django】datatable的button扩展实现纯前端下载和copy指定列内容,以及django的HTTPResponse实现下载功能

 

Table of Contents

功能需求描述

一 使用Datatables实现纯前端下载、拷贝

二 query db 实现下载(django)


 

 

功能需求描述

用户需要以网页为媒介,从DB里拉取一些数据。

分为两种情况:

  • data已经显示在页面上 (除了下载还需要拷贝其中某一列)
  • data没有显示在页面上,需要在trigger download的功能时,根据用户给定的条件,去后台query data,然后下载下来。

 

一 使用Datatables实现纯前端下载、拷贝

对于第一种情况,由于data是通过datatables插件展示的,且已经从DB拉到了页面上,也就没有必要为了下载它们再跑到查询一遍数据库了。

datatables已经给了我们封装好的插件:

(link:https://datatables.net/extensions/buttons/examples/html5/simple.html  )

除了“XXHtml5”以外,还有  copyexcelcsvand pdf 四种。它们与XXHtml5之间的区别暂时还没有搞清楚。

我使用的是“csv”button,只是这样写就可以实现下载的功能:

 table = $('#psumsTable').DataTable( {//不能使用.dataTable。二者返回值不同。在这里我们需要使用datatable插件自带的api,因此必须使用DataTable。

//...
"dom": '<"user_button"B>ptlTgi',//指定button到datatable的左上角。会自动生成一个user_button的div,将所有的button包裹起来
 "buttons": [ 
        {extend: 'csv', //button的功能,包括csv,copy,excel等。这里不能自由发挥,只能使用datatables插件定好的值
        text:'export' //button上显示的文字
        }
    ],

很简单,但接下来在实现copy指定的某一行时遇到了困难。因为默认情况下,该功能会将datatable中所有的行和列都导出/拷贝出来。但我只要其中一列呀,其他的必须去掉。

于是去研究copy的文档:

也就是说,datatable的button插件提供customize选项。该选项提供三个参数: 被拷贝的data(字符串类型),button 配置对象,以及Datatables的API实例,这个实例是当前button所属的那个datatable插件的,也就是说,就是我要从中拷贝数据的那个datatable实例。

而它返回的是什么呢? The value that the function returns is the value that will be used for the export.也就是会被拷贝的数据。

也就是说,我可以使用这个option给我的Datatables API实例(第三个参数),找到我想要下载的那一列,作为返回值返回即可。

最终的code大致如下:

"buttons": [  
        {extend: 'copy', text: 'Copy',
         customize: function(data, config, api){
            var copy_list = api.column('need_copy:name').data();//注意name的用法。这里通过这种方式来让api找到我想copy的那一列
            var copy_data = copy_list .join('\n');  //换行
            alert('Copied to ClipBoard!'); //一个提示,有没有都行。
            return copy_data;
            }
        },

        {extend: 'csv', text:'export'} //下载功能。前面提到了。
    ],
//...
 "columns": [
    //...
     { "data": "column_n", "name": 'need_copy' },

注意上例中的api.column('need_copy:name').data()。因为实现这个功能还有一个坎儿:如何找到我要的那一列。

这就要查Datatables的column-selector了: https://datatables.net/reference/type/column-selector

同样的,csv等button也有customize选项。也可以实现类似的定制化功能。

 

二 query db 实现下载(django)

以前是这样实现的:

step1:根据前台传回来的搜索条件,到db里头query data。

step2:使用FileResponse下载下来。

代码也很简单,网上一搜一大把:

from django.http import FileResponse
import pandas as pd

conn = pymssql.connect(...)  # 连DB
df = pd.read_sql(sql, conn)  # query出来的data存在df中。df是dataframe

df.to_csv(csv_file, encoding='utf_8_sig')  # csv_file是文件路径。

# add data to response
file = open(csv_file, 'rb')
response = FileResponse(file)
response['Content-Type'] = 'application/octet-stream'
response['Content-Disposition'] = 'attachment;filename="%s"' % output_file_name

前台js的话只需要location.href = XXX, 让上面这段代码可以执行就行了。

氮素!

这里头有一个隐形天坑!

注意到这句code了没有:

df.to_csv(csv_file, encoding='utf_8_sig')

它是将从db中拉出来的data先以csv格式保存在某个地方,然后再在后面打开使用FileResponse,将其传递给浏览器,让用户下载。

不是,我都要下载了,还找个地方存文件干嘛??脱裤子放屁???

但这一次万能的度娘没能直接告诉我答案。网络上能查找到的例子,多是将已经存在的文件下载下来。

我就不能直接把dataframe里头的data直接下载下来吗????(仰天长啸!)

于是浅浅地翻阅了一下django的官方文档:

https://docs.djangoproject.com/en/dev/ref/request-response/

HttpResponse 条目下:

嗯?因缺思厅。

那么这个“my_data”从哪里搞呢?

再去百度dataframe的to_csv()的文档:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_csv.html

也就是说,如果我不对to_csv指定输出文件名,它就会将csv data以字符串的形式返回出来。

这不就是我要的my_data么!

然后就很顺利了:

    output_file_name = ''  # 这个文件名给用户看的,会在浏览器中显示
    response = HttpResponse(df.to_csv(encoding='utf_8_sig'))
    response['Content-Type'] = 'application/octet-stream'
    # response['Content-Type'] = 'text/csv'
    response['Content-Disposition'] = 'attachment;filename="%s"' % output_file_name

齐活~

另外,有关content_type和content_description的资料:

http://tools.jb51.net/table/http_content_type/

https://www.jianshu.com/p/4c52cb691f54

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章