flask+vue:創建一個數據列表並實現簡單的查詢功能(一)


之前寫過一個數據構造工具,當時用的Django+vue,后來又用flask重寫了一下后端邏輯

本次打算在現有基礎上加點東西:新增一個數據列表,數據列表中展示曾經創建好的數據

拆解下這次要做的功能:

1、每創建一次數據,都把數據寫到數據庫中;

2、從數據庫中查詢創建好的數據返給前端;

3、前端構建一個數據列表,把后端數據渲染到列表中;

4、數據列表添加查詢功能;

5、數據列表添加分頁功能

1、添加查詢功能

在頁面添加列表查詢功能,我需要構造2個查詢條件:

【數據類型】,把它做成下拉框形式,篩選對應類型的數據

【創建日期】,通過日期篩選創建日期在所選時間范圍內的數據

 

點【查詢】會把對應參數傳到請求中,篩選符合條件的結果;

點【重置】會清空查詢框輸入的條件;

 

這里要用到element-ui中Select 選擇器Form 表單DatePicker 日期選擇器

 

這部分樣式代碼如下

<el-row>
      <el-col :span="24">
        <div class="grid-content bg-purple-dark">
          <el-form :inline="true" :model="form" size="small" ref="ruleForm" class="demo-form-inline" style="margin-left: 10px">
            
            <el-form-item label="數據類型" prop="class">
              <el-select v-model="form.class" placeholder="請選擇數據類型" clearable>
                <el-option label="電話" value="1"></el-option>
                <el-option label="身份證ID" value="2"></el-option>
                <el-option label="姓名" value="3"></el-option>
              </el-select>
            </el-form-item>
            
            <el-form-item label="創建日期" prop="create_date">
              <el-date-picker
                  v-model="form.create_date"
                  type="daterange"
                  range-separator="至"
                  start-placeholder="開始日期"
                  end-placeholder="結束日期"
                  value-format="yyyy-MM-dd HH:mm:ss"
                  :default-time="['00:00:00', '23:59:59']">
              </el-date-picker>
            </el-form-item>
            
            <el-form-item>
              <el-button type="primary" @click="submitForm('ruleForm')">查詢</el-button>
              <el-button @click="resetForm('ruleForm')">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
      </el-col>
    </el-row>

對應的js代碼

<script>
  export default {
    data() {
      return {
        form: {
          class: '',
            create_date: '',
        }
      }
    },
      
    methods: {
      submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          
          let payload = {          // 定義請求參數
            class_type: this.form.class,
            create_date: this.form.create_date
          }
          
          console.log("打印查詢條件輸入的參數payload")
          console.log(payload)
          
          console.log("打印日期框選擇框填寫的日期")
          console.log(this.form.create_date)
          
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    },
    }
  }
</script>

實現效果

  

代碼說明:

1、點擊【重置】,能夠清空輸入框輸入的內容

在js代碼中創建了2個方法submitForm()resetForm(),分別綁定到【查詢】【重置】按鈕

如果想實現點擊【重置】清空內容,需要給表單添加添加ref屬性prop屬性

ref的值 是調用 submitForm() 和 resetForm() 時傳入的值,比如ref="form_data",則調用resetForm()時需要傳入ref,即resetForm('form_data') 

prop的值 是對應表單組件model的值,比如<el-select>中v-model="form.class",所以它對應的prop="class"

2、日期控件 DatePicker 的使用配置

日期這塊期望實現這樣一種效果:選擇開始日期-結束日期后,例如2022-01-13~2011-01-15后,接口傳參為 2022-01-13 00:00:00~2022-01-15 23:59:59

 

在element-ui官方文檔中,可以找到相關配置參數

 

使用value-format指定綁定值的格式,

例如value-format="yyyy-MM-dd HH:mm:ss"

 

使用default-time 指定起始日期的時刻與結束日期的時刻,

例如:default-time="['00:00:00', '23:59:59']"

3、定義請求參數,查看一下前端傳的參數的具體值是什么樣的

submitForm()方法中先定義了查詢接口觸發時所需的參數:一個是數據類型,一個是創建日期

class_type表示數據類型,create_date表示創建日期

它們分別獲取前端傳來的參數,打印一下結果

 

可以看到create_date是一個包含開始日期和結束日期數組,

接下來再看一下參數為空的清空

(1)數據類型、創建日期默認為空時,傳的參數如下

create_date的值為''

(2)數據類型、創建日期先填寫值再重置,傳的參數如下

create_date的值為['']

 

可以看到創建日期默認為空時,傳的值為''

先賦值再重置,傳的值為['']

所以后端處理create_date為空的情況時需要考慮這種情況

2、添加列表

使用Table 表格組件添加一個列表展示數據

樣式代碼

    <el-table
        :data="tableData"
        border
        height="350"
        style="width: 100%; margin-top: 30px;margin-left: 10px">
      <!-- height 表格默認高度,添加height屬性,即可實現固定表頭的表格

      -->
      <el-table-column
          type="index"
          width="50">
      </el-table-column>
      <el-table-column
          prop="date"
          label="日期"
          width="180"
          align="center">  <!--使用align控制對齊方式-->
      </el-table-column>
      <el-table-column
          prop="type"
          label="類型"
          width="180"
          align="center">
      </el-table-column>
      <el-table-column
          prop="value"
          label="生成的測試數據"
          align="center">
      </el-table-column>
    </el-table>

上述代碼中,在<el-table-column>中,使用 align="center" 控制每列標題的對齊方式,

:data="tableData",表示往列表中插入的數據

 

對應js代碼

<script>
  export default {
    data() {
      return {
        tableData: [{
          date: '2022-01-10',
          type: '電話號碼',
          value: '13140845519'
        }, {
          date: '2022-01-10',
          name: '電話號碼',
          value: '18136773435'
        }, {
          date: '2022-01-10',
          type: '電話號碼',
          value: '14592741294'
        }]
      }
    }
  }
</script>

上述代碼中tableData表示往列表中插入的數據,目前是一些假數據,等下從后端獲取到數據后,需要把數據包裝成這種格式賦給tableData

 

3、添加分頁功能

使用 Pagination 分頁 組件給列表進行分頁

樣式代碼

<div class="block" style="margin-top: 10px; text-align: right;"> <!--使用text-align控制div右對齊-->
      <el-pagination
          background
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page.sync="currentPage"
          :page-sizes="[5, 10, 20, 30, 50]"
          :page-size="5"
          layout="total, sizes, prev, pager, next, jumper"
          :total="parseInt(count)">
      </el-pagination>  
</div>

對應js代碼

<script>
  export default {
   data() {
     return {
       form: {
         class: '',
         create_date: '',
       },
       currentPage: 1,
       pageSize:5,
       count: null,
       tableData: null
     };
    },
    methods: {
      handleSizeChange(val) {
      console.log(`每頁 ${val} 條`);
      this.pageSize = val
      console.log("打印當前的pageSize")
      console.log(this.pageSize)
    },
      handleCurrentChange(val) {
        console.log(`當前頁: ${val}`);
      },
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          if (valid) {

            let payload = {          // 定義請求參數
              class_type: this.form.class,
              create_date: this.form.create_date,
              page_num: this.currentPage,
                page_size: this.pageSize
            }

            console.log("打印查詢條件輸入的參數payload")
            console.log(payload)

            console.log("打印日期框選擇框填寫的日期")
            console.log(this.form.create_date)

          } else {
            console.log('error submit!!');
            return false;
          }
        });
    }
    }
  }
</script>

在分頁組件中,需要用到幾個參數:總數據條數total(共xx條)、每頁條數page-size、當前頁碼current-page

 

其中總數據條數是根據當前查詢條件查詢后后端返回的數據總量;

當前頁碼、每頁條數這2個參數需要跟着請求發送,后端根據參數來返回對應查詢結果

 

上述js代碼中,在data()下新增了4個參數:

其中count用來接收后端返回的數據總量,它的值必須為整數

tableData用來接收接口返回並處理后的列表數據

 

其中currentPagepageSize,分別表示當前頁碼和每頁條數,等會兒給請求傳參時,我們會用到它倆,所以我們用這2個參數接收前端的current-page和page-size

我期望達到的效果是當選擇每頁條數或者切換頁碼時,這個2個參數能夠傳給后端實時的數值

這里有2種實現方式,一種是利用.sync 修飾符,一種是利用size-change或者current-change事件

 

(1)利用.sync 修飾符

html中,給當前頁碼參數current-page通過.sync 修飾符綁定currentPage

這樣當前頁碼變化時,currentPage也會獲取到最新的值

(2)利用size-change事件

上述js代碼中,在method()中添加了一個方法handleSizeChange()方法,它的回調參數就是每頁條數

 

然后在前端組件中用@size-change綁定這個事件,那么當每頁條數發生變化時,就會觸發這個事件,回調參數即是當前的每頁條數

 

handleSizeChange()中,我把回調參數val的值賦給pageSize參數,

這樣pageSize就能得到最新的每頁條數了

可以直接把val賦給pageSize:this.pageSize = val

同時,在組件中仍然要給page-size賦一個初始值,這樣每次刷新頁面,當前每頁條數就顯示這個定義的初始值

最后觀察submitForm()方法,我在payload對象中添加了2個參數page_numpage_size,這倆參數其實是我傳給后端請求接口中的2個參數

 

它們分別接收data()中的currentPagepageSize的值

在控制台打印下結果,可以看到每次切換當前條數和頁碼,都能獲取到最新的值

 

4、后端處理

前端代碼先寫到這里,接下來先在后端把接口定義出來

我們需要定義一個接口來供前端調用,根據前端傳參,來返回列表所需的數據

前端會傳4個參數:class_typecreate_datepage_numpage_size

 

因為數據創建好后存到了數據庫中,所以我們需要從數據庫中查出數據返給前端

 

編寫sql時需要考慮到如下幾點:

  • 當某個查詢條件為空時,sql語句中則不加這個條件;
  • 當處理日期時,需要考慮前端日期組件傳來空值的情況(在上面提了一下,前端創建日期如果默認為空時,傳的值為'';如果先選擇日期再重置,傳的值為['']);
  • 日期存在數據庫為datetime對象,期望顯示在前端時經過格式化,按照"年-月-日"顯示;
  • 因為涉及到分頁,根據前端請求參數,控制查詢第一頁數據、第二頁數據等以及每頁數據條數;

創建一個藍圖,data_list.py

# coding: utf-8
"""
author: hmk
detail: 
create_time: 
"""

from flask import Blueprint
from flask_restful import Api, Resource
from flask import request
from utils.connect_db import MysqlConnect
import time

select_data_bp = Blueprint('select_data', __name__)  # 創建一個藍本
api = Api(select_data_bp)  # 使用這個藍本創建一個Api對象


class SelectData(Resource):

    def __init__(self):
        self.db = MysqlConnect()

    def get(self):
        """列表查詢接口"""
        class_type = request.args.get("class_type")  # 獲取前端參數"type"
        create_date = request.args.getlist("create_date[]")  # 獲取前端傳來的list格式數據(前端叫做array,數組)
        page_num = int(request.args.get("page_num"))  # 當前頁碼
        page_size = int(request.args.get("page_size"))  # 每頁顯示數據條數
        print("********************")
        # print(class_type)
        print(create_date)
        # print(page_num)
        # print(page_size)
        # print(type(page_num))

        class_type_data = {  # 定義一個字典,映射數據類型與類型編號的關系
            "1": "電話號碼",
            "2": "身份證id",
            "3": "姓名"
        }

        sql1 = None
        sql2 = None

        if class_type == "":
            if not create_date or create_date == ['']:
                sql1 = "select type_name, value, date_format(create_time, '%Y-%m-%d') from data_list LIMIT {},{}"\
                       .format((page_num-1)*page_size, page_size)

                sql2 = "select count(*) from data_list;"
            else:
                startDate = create_date[0]  # request.args.get("startDate")
                endDate = create_date[1]  # request.args.get("endDate")
                sql1 = "select type_name, value, date_format(create_time, '%Y-%m-%d') from data_list where " \
                       "create_time between '{}' AND '{}' LIMIT {},{};"\
                       .format(startDate, endDate, (page_num-1)*page_size, page_size)

                sql2 = "select count(*) from data_list where create_time between '{}' AND '{}';"\
                       .format(startDate, endDate)

        elif class_type != "":
            if not create_date or create_date == ['']:
                sql1 = "select type_name, value, date_format(create_time, '%Y-%m-%d') from data_list " \
                       "where type_name='{}' LIMIT {},{};"\
                       .format(class_type_data[class_type], (page_num-1)*page_size, page_size)

                sql2 = "select count(*) from data_list where type_name='{}';".format(class_type_data[class_type])

            else:
                startDate = create_date[0]  # request.args.get("startDate")
                endDate = create_date[1]  # request.args.get("endDate")
                sql1 = "select type_name, value, date_format(create_time, '%Y-%m-%d') from data_list " \
                       "where type_name='{}'" \
                       "and create_time between '{}' AND '{}' LIMIT {},{};"\
                       .format(class_type_data[class_type], startDate, endDate, (page_num-1)*page_size, page_size)

                sql2 = "select count(*) from data_list " \
                       "where type_name='{}'" \
                       "and create_time between '{}' AND '{}';".format(class_type_data[class_type], startDate, endDate)

        print("################### 打印sql1 #########################")
        print(sql1)

        history_data = self.db.select_all(sql1)
        print("################### 打印查詢到的所有數據 #########################")
        print(history_data)

        print("################### 打印sql2 #########################")
        print(sql2)

        count = self.db.select_one(sql2)[0]
        print("################### 打印查詢到的數據總條數 #########################")
        print(count)

        self.db.close()
        data = {
            "code": 200,
            "records": history_data,
            "count": count
        }
        time.sleep(0.5)
        return data


api.add_resource(SelectData, '/api/select_data')

代碼說明:

(1)sql1是用來查詢數據的,查出來后,返回給前端,渲染到列表中;sql2是用來查詢數據總量的,顯示當前查詢條件下共有多少條數據;

(2)這里定義該接口為get請求,所以用request.args.get來獲取前端傳來的參數;

注意:在提取日期參數時,是這樣提取的

create_date = request.args.getlist("create_date[]")

因為前端傳來的create_date數組,並且這個是get請求,所以flask在提取這種參數時需要使用getlist

(3)處理分頁時,在sql中使用LIMIT來實現返回對應數據,如下

 

假如每頁顯示10條,那么

第1頁的數據為1~10,

第2頁的數據為11~20,

第3頁的數據為21~30,依此類推

 

對應到sql中limit方法下,

第1頁數據為limit 0, 10; 從第1行開始,檢索10條記錄

第2頁數據為limit 10, 10; 從第11行開始,檢索10條記錄,也就是11~20

第3頁數據為limit 20, 10; 從第21行開始,檢索10條記錄,也就是21~30

 

了解這個對應關系后,我們從前端獲取到 當前頁碼 page_num每頁顯示數據條數page_size后,就可以寫出如下sql

這里查出來的數據為元組,如果直接返回到前端會解析為列表

前端請求后,接口返回如下

5、前端發送請求,處理接口返回數據

submitForm()方法中添加axios發送請求

submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          let url1 = "http://127.0.0.1:5000/"
          let payload = {                  // 定義請求參數
            class_type: this.form.class,
            create_date: this.form.create_date,
            page_num: this.currentPage,
            page_size: this.pageSize
          }
          console.log("打印查詢條件輸入的參數payload")
          console.log(payload)
          console.log("打印日期框選擇框填寫的日期")
          console.log(this.form.create_date)
          axios({
            timeout: 10000,
            method: "get",
            params: payload,  //發送get請求,使用params關鍵字接收請求參數
            url: url1+"api/select_data"
          }).then(res => {
            console.log(res.data.records)  //打印返回的原始數據
            let data_list = res.data.records.map(function(array) {
              let rObj = {};
              rObj["date"] = array[2]
              rObj["type"] = array[0]
              rObj["value"] = array[1]
              return rObj;})
            console.log(data_list)
            this.tableData = data_list
            // let data_count = res.data.count
            this.count = res.data.count

            // console.log(data_list)
            // console.log(data_count)

            if(res.data.code === 200){  //判斷響應中的code是否為200
              // console.log(res.data)

              this.$message({   // 接口調用成功后,添加頁面toast提示
                message: '接口調用成功',
                type: 'success'
              });
            }
            else{
              console.log(res.data)
            }
          }).catch((reason)=>{
            console.log(reason)
            this.$message({
              message: '接口調用失敗,請檢查系統是否正常',
              type: 'warning'
            });
          })
          // console.log(typeof this.currentPage)
        } else {
          console.log('error submit!!');
          return false;
        }
      });
    },

代碼說明:

1、res.data.records 是發送請求后返回的原始數據,即接口中定義的records

但是它的格式如下,不能直接給前端列表用

前端列表需要如下格式的數據

所以我們需要把里面一個個小的數組轉換為對象

可以通過map來實現,代碼如下

在map中定義了一個函數,它的作用就是構造一個對象,分別用date、type、value作為鍵,然后分別賦上接口返回數組中每個小數組對應的值,這樣處理后,接口返回的數組就變為了如下形式

2、this.count = res.data.count

它的作用是把接口返回的數據總數賦給count

之前在分頁組件中我們把count的值賦給了total,如下

到這里為止,基本目的就達到了,從后端取出數據渲染到前端,同時可以分頁、顯示數據總量、並且可以查詢

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM