美文网首页
datatables折腾日志

datatables折腾日志

作者: zhym1992 | 来源:发表于2017-11-27 11:36 被阅读0次

    https://github.com/ygidtu/Flask-peewee-datatables上我挂了一个demo

    datatables:官网【https://datatables.net/】

    datatables做用展示
    如上图所示,datatables是一个非常好用的js库,方便在网页中展示各种结果

    一、安装

    Download:https://datatables.net/download/index
    我常用两种:

    • 下载到本地以static文件的方式引入,但是,除了默认主题,其他的主题会存在图片定位不到的问题
    • CDN

    二、基础用法

    官方最简单的教学:https://datatables.net/examples/basic_init/zero_configuration.html
    什么都不加,直接在HTML页面中生成一个table,

     <table id="tfbs">
      <thead>
        <tr>
          <th>id</th>
          <th>chrom</th>
          <th>start</th>
          <th>end</th>
          <th>eid</th>
          <th>tissue</th>
          <th>order</th>
          <th>predict</th>
        </tr>
      </thead>
        <tbody></tbody>
    </table>
    

    然后直接通过JQuery调用DataTable即可,直接使用

    $(document).ready(function() {
        $('#tfbs').DataTable( );
    } );
    

    当然,各种细节也可以自行调整,具体请自行查询官方文档


    三、ajax

    当然,这种成熟的JS库当然支持ajax的用法,它需要有特定的ajax格式
    所需要的特定的json格式,格式如下:这只是非常基本的格式之一

    {
      "draw": 1,
      "recordsTotal": 57,
      "recordsFiltered": 57,
      "data": [
        [
          "Airi",
          "Satou",
          "Accountant",
          "Tokyo",
          "28th Nov 08",
          "$162,700"
        ]
      }
    

    ajax的JavaScript脚本如下:

    $(document).ready(function() {
        $('#example').DataTable( {
            "processing": true,
            "serverSide": true,
            "ajax": {
                "url": "scripts/jsonp.php",
                "dataType": "jsonp"
            }
        } );
    } );
    

    三、Flask的配合问题

    现成的Flask的API支持flask-rest、flask-restful和flask-peewee都无法修正为datatables的格式,因此,还是得自己动手丰衣足食
    为了能够ajax的交互操作,必须搞清楚datatables是通过何种方式向服务器传递参数的

    • 最基础的,datatables会通过在url后附加各种参数来完成数据传递
    • 可以自己指定向api借口post数据

    1. 拆分url参数

    以最开始的例子为例,我开了一个/api/enhancer的接口,默认datatables会通过如下的url获取数据

    GET /api/enhancer/?draw=17&columns%5B0%5D%5Bdata%5D=id&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=chrom&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B2%5D%5Bdata%5D=start&columns%5B2%5D%5Bname%5D=&columns%5B2%5D%5Bsearchable%5D=true&columns%5B2%5D%5Borderable%5D=true&columns%5B2%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B2%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B3%5D%5Bdata%5D=end&columns%5B3%5D%5Bname%5D=&columns%5B3%5D%5Bsearchable%5D=true&columns%5B3%5D%5Borderable%5D=true&columns%5B3%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B3%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B4%5D%5Bdata%5D=eid&columns%5B4%5D%5Bname%5D=&columns%5B4%5D%5Bsearchable%5D=true&columns%5B4%5D%5Borderable%5D=true&columns%5B4%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B4%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B5%5D%5Bdata%5D=tissue&columns%5B5%5D%5Bname%5D=&columns%5B5%5D%5Bsearchable%5D=true&columns%5B5%5D%5Borderable%5D=true&columns%5B5%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B5%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B6%5D%5Bdata%5D=order&columns%5B6%5D%5Bname%5D=&columns%5B6%5D%5Bsearchable%5D=true&columns%5B6%5D%5Borderable%5D=true&columns%5B6%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B6%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B7%5D%5Bdata%5D=myself&columns%5B7%5D%5Bname%5D=&columns%5B7%5D%5Bsearchable%5D=true&columns%5B7%5D%5Borderable%5D=true&columns%5B7%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B7%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=5&order%5B0%5D%5Bdir%5D=desc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&_=1510720968919
    

    返回的数据data类,如下:


    返回的数据格式

    目前,已经拆分出几个参数

    • draw:页数,所需第几页的数据
    • %5B、%5D:
    • columns%5B0%5D%5Bdata%5D=id:
      • 原义为columns[0][data]=id,经过cprint(get_parameter("columns[0][data]"), 'red')证实,确实如此。这一大段,表明我的表格的第一列使用的是json中key值为id的这一项的数据,
    • columns%5B0%5D%5Bname%5D=:
      • columns[0][name]=,这一项不是何意,估计是可以该列名
    • columns%5B0%5D%5Bsearchable%5D=true:
      • columns[0][searchable]=true,能够查询
    • columns%5B0%5D%5Borderable%5D=true:
      • columns[0][orderable]=true,该列能够排序
    • columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=:
      • columns[0][search][value]= ,按照什么数据来查询该列
    • columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false:
      • columns[0][search][regex]=false,该列是否通过正则来匹配
    • 然后重复,因此,通过这些调整就将各行各列的所有数据都调整好了

    2. 参数的详细用法

    首先,将数据只调整到一列,开始解析各个参数的详细用法

    order

    通过调整order调整到这样一条url

    api/enhancer/?draw=1&columns%5B0%5D%5Bdata%5D=id&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=0&order%5B0%5D%5Bdir%5D=asc&start=0&length=10&search%5Bvalue%5D=&search%5Bregex%5D=false&_=1510727303124
    

    order%5B0%5D%5Bcolumn%5D=0&order%5B0%5D%5Bdir%5D=asc:
    order[column]=0&order[0][dir]=asc或者dir=desc

    • draw:第几次向该api发出请求
    • order:column指定第几列调整顺序,order[0][dir=asc]或者order[0][dir=desc]指定排序方式
    • start=0&length=10,length 代表每一页上有多少数据,start是这一页最开始的那一条是第几条

    search

    GET /api/enhancer/?draw=13&columns%5B0%5D%5Bdata%5D=id&columns%5B0%5D%5Bname%5D=&columns%5B0%5D%5Bsearchable%5D=true&columns%5B0%5D%5Borderable%5D=true&columns%5B0%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B0%5D%5Bsearch%5D%5Bregex%5D=false&columns%5B1%5D%5Bdata%5D=chrom&columns%5B1%5D%5Bname%5D=&columns%5B1%5D%5Bsearchable%5D=true&columns%5B1%5D%5Borderable%5D=true&columns%5B1%5D%5Bsearch%5D%5Bvalue%5D=&columns%5B1%5D%5Bsearch%5D%5Bregex%5D=false&order%5B0%5D%5Bcolumn%5D=1&order%5B0%5D%5Bdir%5D=asc&start=0&length=10&search%5Bvalue%5D=chr1&search%5Bregex%5D=false&_=1510727522537 HTTP/1.1
    

    不出所料

    • search%5Bvalue%5D=chr1
      • search[value]=chr1

    3. Python配置

    通过以上的参数,相信参数的事情就解析清楚了,那么就可以自行动手,设计API来处理这些数据了,我使用的是peewee来处理底层的数据库,因此,写了一个类来处理这个问题

    用法已经放在github库上了:https://github.com/ygidtu/Flask-peewee-datatables

    #!/usr/bin/env python3
    # -*- coding:utf-8 -*-
    u"""
    serverside的datatables配合flask和peewee使用的方法
    """
    import re
    from collections import OrderedDict
    from flask import request
    from peewee import BooleanField
    from peewee import IntegerField
    from peewee import FloatField
    
    
    # flask配合datatables使用的类
    class WorkWithDataTables(object):
        u"""
        2017.11.15
        开始设计类,想办法自行处理dtatables返回的参数
        """
    
        def __init__(self, table, columns=None, join=None):
            u"""
            初始化
            :param columns: 列表,传入查询的columns, 如果不指定columns,默认使用表中所有的列
            :param join: 列表,传入查询的如果需要join表,可以通过这个join指定实现,目前只能join一个表
            """
            # 构建
            if columns is None:
                columns = list(table._meta.fields.values())
    
                if join:
                    columns += list(join._meta.fields.values())
    
            start = 0
            tem = []
            for i in columns:
                tem.append([start, i])
                start += 1
            self.columns = OrderedDict(tem)
            self.table = table
            self.join = join
    
        @staticmethod
        def get_parameter(label, default=None):
            u"""
              :param label: url中指定的参数是
              :param default: 如果url中没有这个参数,返回的默认值,一般为None
              :return:返回strip之后的参数
             """
            tem = request.args.get(label)
    
            if tem is None:
                return default
            return tem.strip()
    
        def _searchable_(self, index):
            u"""
            datatables可以通过JavaScript的设置指定某些列可以被查询,某些不可以,
            于是变有了这个函数,只有能够被查询的列,我才会查询
            """
            if self.get_parameter("columns[%d][searchable]" % index) == "true":
                return True
            else:
                return False
    
        def _set_order_(self):
            u"""
            根据datatables提交的参数,判定查询结果的排序方式
            :return: 返回特定排序方式的peewee Expression语句
            """
            # 指定排序方式
            order = self.get_parameter("order[0][column]")
            order_by = None
    
            if order:
                order = int(order)
                order_by = self.columns.get(order)
                order_dir = self.get_parameter("order[0][dir]")
    
                if order_by and order_dir == "desc":
                    order_by = order_by.desc()
    
            return order_by
    
        def _set_search_(self):
            u"""
            根据url参数,设定查询的语句
            :return:peewee的查询Expression语句
            """
            # 指定查询的值是多少
            search = self.get_parameter("search[value]")
    
            # 判断一下输入的是否是boolean值,true、false、yes、no均可,不分大小写
            if search is not None:
                if re.search(r"^(true|yes)$", search, re.I):
                    search = True
                elif re.search(r"^(false|no)$", search, re.I):
                    search = False
                else:
                    search = search
            #指定查询的peewee Expression语句
            search_condition = None
            if search:    #如果开启search需求
                for i in self.columns:    # 遍历所有的列,然后分别根据特定情形指定查询语句,目前仅支持bool、float、int
                    if self._searchable_(i):
                        # 如果遇到布尔型,需要独特的处理方法
                        if isinstance(self.columns[i], BooleanField) and\
                                not isinstance(search, bool):
                            if search_condition is None:
                                search_condition = (self.columns[i] == None)
                            else:
                                search_condition = (
                                    self.columns[i] == None) | search_condition
                            continue
    
                        # if this column is integer type
                        if isinstance(self.columns[i], IntegerField):
                            try:
                                search = int(search)
                                if search_condition is None:
                                    search_condition = (self.columns[i] == search)
                                else:
                                    search_condition = (
                                        self.columns[i] == search
                                    ) | search_condition
                            except:
                                continue
                            continue
    
                        # if this column is float type
                        if isinstance(self.columns[i], FloatField):
                            try:
                                search = float(search)
                                if search_condition is None:
                                    search_condition = (self.columns[i] == search)
                                else:
                                    search_condition = (
                                        self.columns[i] == search
                                    ) | search_condition
                            except:
                                continue
                            continue
    
                        # 如果符合要求就不用管了,正常处理即可
                        if search_condition is None:
                            search_condition = (
                                self.columns[i].regexp(str(search) + ".*"))
                        else:
                            search_condition = (self.columns[i].regexp(
                                str(search) + ".*")) | search_condition
            return search_condition
    
        def query(self, condition=None, search=True, order=None, **kwargs):
            u"""
            查询语句
            :param condition: 外部指定的特定查询要求,peewee Expression
            :param search: boolean值,在后期是否能支持datatables的查询框输入值查询
            :param order: 指定初始化的顺序,如果不设定,就使用默认顺序
            :return: 
            """
            # 获取参数
            page = int(self.get_parameter("start", 1)) / 10 + 1
            per_page = int(self.get_parameter("length", 10))
            draw = int(self.get_parameter("draw", 1))
    
            querys = self.table.select(*self.columns.values())
    
            if order:
                querys = querys.order_by(order)
    
            # 指定非第一次的查询,才会通过这个排序方式排序
            if draw > 1:
                order = self._set_order_()
                querys = querys.order_by(order)
    
            # 如果有外链表,就外链
            if self.join:
                querys = querys.join(self.join)
    
            # 如果有查询条件或者搜索条件,就分别指定不同的条件
            if condition and search:
                search_condition = self._set_search_()
    
                if search_condition:
                    condition = condition & search_condition
            elif search:
                condition = self._set_search_()
    
            if condition:
                querys = querys.where(condition)
            
            # 如果有的表数据量比较大,查询起来特别慢,就可以手动指定一个值,加快速度
            if kwargs.get("total") is not None:
                total = kwargs["total"]
            else:
                total = querys.count()
            querys = querys.paginate(page, per_page)
            
            # 构建最终的json文件
            data = [x for x in querys.dicts()]
    
            return {
                "data": data,
                "draw": draw,
                "start": page,
                "length": per_page,
                "recordsTotal": total,
                "recordsFiltered": total
    }
    

    相关文章

      网友评论

          本文标题:datatables折腾日志

          本文链接:https://www.haomeiwen.com/subject/damcvxtx.html