• vue-element-admin+flask实现数据查询项目


    本文分享一个使用vue-element-admin+flask实现的一个数据查询项目,

    填写数据库连接信息和查询语句,即可展示查询到的数据。

     

    前提:已下载vue-element-admin并编译成功

    前端

    1、添加路由

    src-router-index.js添加路由

    1. {
    2. path: '/idata',
    3. component: Layout,
    4. redirect: '/idata/index',
    5. hidden: false,
    6. children: [
    7. {
    8. path: 'index',
    9. component: () => import('@/views/idata/index'),
    10. name: 'idata',
    11. meta: { title: 'iData设置', icon: 'list', noCache: true }
    12. }
    13. ]
    14. },

    2、添加页面元素

    在src-views下新建idata目录,目录下新建index.vue

    1. <script>
    2. import { getConnect, doConnect, exec } from '@/api/idata'
    3. export default {
    4. name: 'idata',
    5. data() {
    6. return {
    7. rules: {
    8. db_host: [
    9. { required: true, message: '请输入域名', trigger: 'blur' }
    10. ],
    11. db_port: [
    12. { required: true, message: '请输入端口', trigger: 'blur' }
    13. ],
    14. db_user: [
    15. { required: true, message: '请输入用户名', trigger: 'blur' }
    16. ],
    17. db_passwd: [
    18. { required: true, message: '请输入密码', trigger: 'blur' }
    19. ],
    20. db_name: [
    21. { required: true, message: '请输入数据库', trigger: 'blur' }
    22. ]
    23. },
    24. title: 'iData设置',
    25. formData: {
    26. db_charset: 'utf8',
    27. db_host: null,
    28. db_port: null,
    29. db_user: null,
    30. db_passwd: null,
    31. db_name: null,
    32. sql: null,
    33. param: {},
    34. key: 'all'
    35. },
    36. tableData: [],
    37. time: 0,
    38. uniqKey: null,
    39. maxCount: 20,
    40. sql: null,
    41. message:null,
    42. tableHead: [],
    43. result:[]
    44. }
    45. },
    46. methods: {
    47. onConnect (formName) {
    48. this.$refs[formName].validate((valid) =>{
    49. if (valid) {
    50. doConnect({
    51. ...this.formData
    52. }).then(res => {
    53. this.uniqKey = res.uniq_key
    54. this.message='连接成功'
    55. this.$message({
    56. message: '连接测试成功!',
    57. type: 'success'
    58. })
    59. })
    60. }
    61. else {
    62. this.$message({
    63. message: '请检查必填字段!',
    64. type: 'error'
    65. })
    66. return false
    67. }
    68. }
    69. )//验证函数结尾
    70. },
    71. onExec (formName) {
    72. this.$refs[formName].validate((valid) =>{
    73. if (valid) {
    74. if (!this.formData.sql) {
    75. this.$message({
    76. message: 'SQL 语句不能为空。',
    77. type: 'warning'
    78. })
    79. return
    80. }
    81. exec({
    82. ...this.formData,
    83. }).then(res => {
    84. if (res.data.length > 0) {
    85. this.tableHead = []
    86. for (let i in res.data[0]) {
    87. this.tableHead.push(i)
    88. }
    89. this.tableData = res.data
    90. this.time = res.time_cost
    91. } else {
    92. this.tableHead = []
    93. this.tableData = []
    94. }
    95. this.message='查询成功'
    96. this.loading = false
    97. this.$message({
    98. message: '查询成功',
    99. type: 'success'
    100. }
    101. )
    102. }
    103. ).catch(err => {
    104. this.loading = false
    105. console.log(err)
    106. this.$message({
    107. type: 'error'
    108. })
    109. })
    110. }
    111. else {
    112. this.$message({
    113. message: '请检查必填字段!',
    114. type: 'error'
    115. })
    116. console.log('error submit!!')
    117. return false
    118. }
    119. }
    120. )//验证函数结尾
    121. }//onconnect函数结尾
    122. }
    123. }
    124. script>

    3、添加请求

    在src-api新建idata.js

    1. import request from '@/utils/request'
    2. export function doConnect (data) {
    3. return request({
    4. url: '/api/test',
    5. method: 'post',
    6. data
    7. })
    8. }
    9. export function exec (data) {
    10. return request({
    11. url: '/api/idata',
    12. method: 'post',
    13. data
    14. })
    15. }

    ----拿到ret结果,根据结果来显示默认按钮/成功按钮。
    ----如何展示查询到的数据呢? 前端实际有一个table,动态读取结果字段显示。
    ----查询数据时,前端一直报错,显示error,控制台显示uncanght promise报错。
    查了一会,才发现是后端返回的ret没有code这个字段,加上就可以了。
    ----如何将textraea输入框宽度增加
    ----弹框消息
      this.$message({
              message: '连接测试成功!',
              type: 'success'
            })
    ----前端方法里的response.data实际是取的返回结果data这个key的值
    ---- this.$refs 用来给标签或者组件添加属性。需要这个标签或者组件中有ref=
     <el-form  :inline="true"  ref="formData" :rules="rules" :model="formData"
    label-width="70px">
    ----控制台可以调试前端代码
    -----form加:rules="rules" 并且在return里写上规则,并且每个el-form-item要有prop,可以实现
    校验必填 其实在el-form这个组件有写对于表单的校验
    -----加了校验后报错 Cannot read properties of undefined (reading 'validate')
    传参需要加引号submit('formName')。
     this.$refs[formName].validate 这一行是对的

     

    后端

    这里只贴主要代码,有时间再继续贴。

    1、添加路由

    app.py添加

    1. app.route('/api/idata', methods=['POST'])(idata)
    2. app.route('/api/test',methods=['POST'])(onconnect)

    2、添加函数

    controller下data.py

    1. import json
    2. from flask import request, current_app as app
    3. from constant import SQLTYPE, DBKEYTYPE
    4. from lib.dbpool import DBPool
    5. def idata():
    6. return query(request.json)
    7. def onconnect():
    8. data=request.json
    9. conn_info = warp_db_conn_info(data)
    10. print(conn_info)
    11. db_conn = DBPool.get_conn(**conn_info)
    12. ret = {
    13. "success": False,
    14. "msg": None,
    15. 'code':0
    16. }
    17. if not db_conn:
    18. ret['msg'] = '连接目标DB失败,请确认连接信息是否正确'
    19. ret['code']=-1
    20. else:
    21. ret['msg'] = '连接成功'
    22. ret['success']=True
    23. ret['code']=0
    24. return ret
    25. def warp_db_conn_info(data):
    26. d = {}
    27. keys = ['db_host', 'db_port', 'db_name', 'db_user', 'db_passwd', 'db_charset']
    28. for key in keys:
    29. if key in data and data[key]:
    30. d[key] = data[key].strip() if isinstance(data[key], (str, bytes)) else data[key]
    31. return d
    32. def query(data):
    33. """
    34. 根据DB和SQL信息执行远程查询并返回结果
    35. :param data: {
    36. "db_host": "x.x.x.x",
    37. "db_port": 3306,
    38. "db_name": "test",
    39. "db_user": "root",
    40. "db_passwd": "root",
    41. "db_charset": "utf8",
    42. "sql": "select * from tbl_key_info where id=:id limit 1",
    43. "param": {
    44. "id": 100110
    45. },
    46. "key": "all"
    47. }
    48. :return: {
    49. "success": True,
    50. "data": [{"id": 100110, "xxx", "xxx"}],
    51. "type": "SELECT",
    52. "msg": ""
    53. }
    54. """
    55. app.logger.info(f'query data {json.dumps(data)}')
    56. ret = {
    57. "success": False,
    58. "data": [],
    59. "type": None,
    60. "msg": None,
    61. "code":0
    62. }
    63. if not data:
    64. return ret
    65. conn_info = warp_db_conn_info(data)
    66. # print(conn_info)
    67. db_conn = DBPool.get_conn(**conn_info)
    68. if not db_conn:
    69. ret['msg'] = '连接目标DB失败,请确认连接信息是否正确'
    70. return ret
    71. sql = data.get('sql')
    72. if not sql:
    73. ret['msg'] = '查询语句不能为空'
    74. return ret
    75. # app.logger.info(f'查询语句: {sql}, 查询参数: {data.get("param")}')
    76. app.logger.info(f'查询语句: {sql}, 查询参数: {data.get("param")}')
    77. # rows = db_conn.query(sql, **data.get('param'))
    78. rows = db_conn.query(sql)
    79. results = []
    80. upper_sql = sql.upper().strip()
    81. if upper_sql.startswith(SQLTYPE.INSERT):
    82. sql_type = SQLTYPE.INSERT
    83. elif upper_sql.startswith(SQLTYPE.UPDATE):
    84. sql_type = SQLTYPE.UPDATE
    85. elif upper_sql.startswith(SQLTYPE.DELETE):
    86. sql_type = SQLTYPE.DELETE
    87. elif upper_sql.startswith(SQLTYPE.SELECT):
    88. sql_type = SQLTYPE.SELECT
    89. key = data.get('key', DBKEYTYPE.FIRST)
    90. if key == 'all':
    91. results = rows.as_dict()
    92. else: # 为了减少网络传输,默认只查询一行
    93. first = rows.first()
    94. results = [first.as_dict()] if first else []
    95. else:
    96. sql_type = SQLTYPE.UNKNOWN
    97. ret.update(
    98. {
    99. "success": True,
    100. "data": results,
    101. "type": sql_type,
    102. "msg": '',
    103. 'code':0
    104. }
    105. )
    106. app.logger.info(f'查询结果: {results}')
    107. return ret

    dbpool.py用来进行数据库连接

    1. import records
    2. from urllib import parse
    3. class DBPool:
    4. db_pool = {}
    5. @staticmethod
    6. def get_conn(db_host=None, db_name=None, db_port="3306", db_user='root',
    7. db_passwd='root', db_charset='utf8'):
    8. if db_host is None or db_name is None:
    9. raise ValueError("host and db_name can't be None.")
    10. key = DBPool.make_uniq_key(db_host, db_port, db_name)
    11. if key not in DBPool.db_pool:
    12. sql_str = DBPool.make_conn_str(db_host, db_name, db_port, db_user, db_passwd, db_charset)
    13. print(sql_str)
    14. DBPool.db_pool[key] = records.Database(sql_str, pool_pre_ping=True)
    15. try:
    16. db = DBPool.db_pool[key]
    17. db.query('''select 1''')
    18. except:
    19. db = None
    20. del DBPool.db_pool[key]
    21. return db
    22. @staticmethod
    23. def make_uniq_key(db_host, db_name, db_port):
    24. return f'{db_host}:{db_port}:{db_name}'
    25. @staticmethod
    26. def make_conn_str(db_host, db_name, db_port, db_user, db_passwd, db_charset):
    27. return f'mysql+pymysql://{db_user}:{parse.quote_plus(db_passwd)}@{db_host}:{db_port}/{db_name}?charset={db_charset}'

    今天晚了,改天有时间再详细讲解。

  • 相关阅读:
    LeetCode 643. Maximum Average Subarray I
    AnimalTFDB v4.0 | OMG!我最爱的转录因子数据库更新啦!~(附使用指南)(二)
    [附源码]Python计算机毕业设计Django基于Java的图书购物商城
    安全防御拓扑1
    Mac安装office 2019
    数商云SCM系统订单收货场景介绍,探索采购新模式,提升汽车服务企业运营水平
    Spring5入门到实战------2、IOC容器底层原理
    React.memo()、useCallback()和useMemo()的用法--性能优化--缓存
    React原理揭秘--setState() 的说明,JSX 语法的转化过程,组件更新机制,组件性能优化,虚拟 DOM 和 Diff 算法
    【uniapp】uniapp开发微信小程序入门教程
  • 原文地址:https://blog.csdn.net/seanyang_/article/details/127723231