python3 + Django + Mysql + Vue + Element-UI 学习笔记:从0搭建前后端分离的测试工具平台

 

2021.06.10    INIT
2021.06.24    增加生成图片支持备注文字功能;redis链接方式切换为cluster
2021.06.29    生成图片功能支持中文备注
2021.07.01    修复通过域名访问静态文件类型错误;生成图片增加尺寸信息
2021.07.09    域名接入完成;增加mysqldb记录访问信息;系统信息页面增加访问信息统计功能
2021.07.30    增加支持按掩码查询用户信息
2021.08.05    增加支持发送mq消息功能;mq搜索框支持模糊搜索;查询用户信息增加手机号回显处理
2021.08.11    查询用户信息反查展示真实手机号(掩码反查)
2021.08.12    增加支持优惠券一键发放、作废功能
2021.08.26    增加支持广告位一键同步;发送mq页面;优惠券使用期限调整功能
2021.09.11    增加用户权益查询功能
2021.09.15    新增定时任务功能
2021.09.16    生成图片支持gif格式
2021.09.23    新增留言板,支持留言、回复、分页展示
2021-09-26    生成图片支持自定义背景色、文字颜色
2021-09-29    增加支持权益一键发放功能;优化优惠券发放增加校验
2021-10-29    增加定时任务开启时不可修改的校验;首次开启时,自动执行一次;造数增加积分操作入口
2021-11-08    增加查询用户优惠券列表功能
2021-12-03    增加用户积分查询与修改功能
2021-12-25    节点达标增加手动触发说明、支持用户自行新增节点、编辑节点

2022-01-21    新增业务域管理模块:支持用户自行维护;支持管理员审批。计划从这次开始,新功能写开发记录https://www.cnblogs.com/chenyuebai/p/15830681.html

 


前言

1、概述

此前一直想把测试工作过程中的一些通用的工具、方法、FAQ,集成为一个通用的测试工具。

也尝试过用python的Tkinter做的GUI(有兴趣的话,见: https://www.cnblogs.com/chenyuebai/p/7150382.html

虽然能用,但缺点也很明显:不美观、扩展性差、需要打包下载。

因此,想搭个Web-Browser、前后端分离的测试平台,把测试的一些能力集成上去,顺便学习下前后端开发知识。

功能范围大概包含:

(1)测试数据构造:日常测试、配合联调,需要多次重复的构造测试数据;针对高频操作沉淀出TOP场景,落到测试平台中。供组内同学,或者诉求方使用

(2)常用查询:直接查询库表,一是查询环境需要频繁切换,二是很多字段都是枚举值,需要二次查询字段含义,效率低;在这里把一些通用的查询操作固化下来,代码中将枚举值转义,易于理解

(3)常用链接地图:支持区分环境,含公司通用的研发/测试平台地址、小工具地址、FAQ等

(4)定时任务:支持MYSQL、HTTP、RPC定时执行

(5)MQ MOCK仓库:

2、项目结构

(1)后端:python3 + django + mysql

(2)前端:Vue + Element-UI + Js

3、功能预览:

(1)首页及菜单、系统访问地图:

(2)测试数据构造

 (3)MQ MOCK仓库:

 (4)定时任务

 (5)留言板

 


 

一、环境准备

1、Python 3.6.1
2、Django 2.2.6    pip安装即可
3、mysql 5.7.1 + Connector/J 5.1.48
(1)安装:mysql安装时需记录用户名、密码
(2)配置时间、字符集:

sql cmd:
set global time_zone = '+8:00';  #修改mysql全局时区为北京时间,即我们所在的东8区
set time_zone = '+8:00';          #修改当前会话时区
flush privileges;            #立即生效

installPath\my.ini:
在[client]节点下添加  default-character-set=utf8
在[mysqld]节点下添加 (注:collation是排序方式)  character-set-server=utf8     collation-server=utf8_general_ci
restart
SHOW VARIABLES LIKE 'char%';

 

(3)本地启动mysql服务:

CMD: net start mysql_service_ch

(4)数据库迁移

manage.py makemigrations
manage.py migrate

(5)创建超级用户

manage.py createsuperuser

(6)设置后台管理界面为中文

setting.py中:
LANGUAGE_CODE = 'zh-hans'  
TIME_ZONE = 'Asia/Shanghai'

 

前端开发环境搭建,参考:

https://www.cnblogs.com/goldlong/p/8027997.html

 

二、创建项目、应用

1、创建项目

django-admin.py startproject MySite运行服务:manage.py runserver      本地访问:http://127.0.0.1:8000/
ps:若希望外部机器(同一网络内)访问本机的Django服务 可:manage.py runserver 0.0.0.0:8080
并将setting.py中,ALLOWED_HOSTS = ['*', ]

2、创建应用

manage.py startapp Post

3、目录说明

 

 

4、配置数据库信息

由于选择的是mysql,需要配置数据库信息

MySite/__init__.py:

import pymysql
pymysql.install_as_MySQLdb()

MySite/setting.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mysite',
        'USER':'root',
        "PASSWORD":"passwd123456",
        "HOST":"127.0.0.1",
        "PORT":"3306"
    }
}


至此,环境基本搭建完成;

三、功能实现

大概思路

-->  前端浏览器访问/点击,触发http请求

-->  后端 MySite\urls.py\urlpatterns中寻找路由信息 --> 调用views.py中的视图函数-->处理http请求、参数处理、封装返回 --> 视图函数调用viewImpl中具体的业务代码 --> 数据库处理 --> 组装结果 --> 返回结果至前端

--> 前端页面渲染展示

以查询留言板列表数据的功能为例(部分代码有删改):

1、后端接口开发

(1)接口业务逻辑实现:viewImpl.py 

def queryMsgBoardList(self,msgId,msgType,msgAuthor,pageNb,pageSize):
    msgBoardList = []
    totalCount = None
    # 处理分页
    startIndex = (pageNb-1) * pageSize
    # 组装查询条件
    sqlTemplate = '''select **** from test_**** where trigger_type='MSG_BOARD' {} ORDER BY create_time desc limit {},{};'''
    msgIdCondition = ""
    if msgId and msgId != 'undefined':
        msgIdCondition = " and id='{}'".format(msgId)
    msgTypeCondition = ""
    if msgType and msgType != 'undefined':
        msgTypeCondition = " and detail_info like '%{}%'".format(msgType)
    msgAuthorCondition = ""
    if msgAuthor and msgAuthor != 'undefined':
        msgAuthorCondition = " and detail_info like '%{}%'".format(msgAuthor)
    sqlCondition = msgIdCondition + msgTypeCondition + msgAuthorCondition
    querySql = sqlTemplate.format(sqlCondition,startIndex,pageSize)
    try:
        # 查询留言列表
        sqlRetData = utils.MysqlUtils().executeSql(querySql,"****db_dev")
        No = 1
        for item in sqlRetData:
            detailInfo = json.loads(item[4].replace('\n', '\\r\\n'))
            msgBoard = {"msgId": item[0], "msgType": detailInfo["msgType"],"msgBody": detailInfo["msgBody"],"msgAuthor": detailInfo["msgAuthor"],"createTime": str(item[6]).replace("T", " ")}
            No = No + 1
            msgBoardList.append(msgBoard)
        # 查询总数量(sql中不带入分页条件)
        queryCtSql = "select count(*) from test_**** where trigger_type='MSG_BOARD' {};".format(sqlCondition)
        totalCount = int(utils.MysqlUtils().executeSql(queryCtSql,"coupondb_dev")[0][0])
        Logger.info("queryMsgBoardList success. msgBoardList = {},totalCount={}".format(msgBoardList,totalCount))
    except Exception as e:
        executeResult = str(e) + "\n" + traceback.format_exc()
        Logger.error("queryMsgBoardList 异常:%s" % executeResult)
    finally:
        return msgBoardList,totalCount

 

(2)view层:views.py

def queryMsgBoardList(request):
    # 入参打印
    utils.SysRecord().LoggerInfoBatch(["request = {}".format(request), "request.body = {}".format(request.body),"request.POST = {}".format(request.POST)])
    # 记录访问信息
    utils.SysRecord().visitRecord(request)
    # 定义参数,获取入参
    msgId = request.POST.get("msgId")
    msgType = request.POST.get("msgType")
    msgAuthor = request.POST.get("msgAuthor")
    pageNb = request.POST.get("pageNb")
    pageSize = request.POST.get("pageSize")
    response = {}
    # 校验入参
    if not WorkTools.StringFactory().batchCheckParams([pageNb,pageSize]):
        Logger.error("Post.views.queryMsgBoardList() 校验参数失败,存在入参为空,请检查")
        return utils.DjangoTools().returnResponse({"code": "1", "message": "queryMsgBoardList() 校验参数失败,存在入参为空,请检查"})
    try:
        # 查询留言板数据
        pageNb = int(pageNb)
        pageSize = int(pageSize)
        msgBoardList,totalCount = viewImpl.MsgBoard().queryMsgBoardList(msgId,msgType,msgAuthor,pageNb,pageSize)
        # 组装结果返回
        response["code"] = "0"
        response["message"] = "查询成功"
        response["msgBoardList"] = msgBoardList
        response["totalCt"] = totalCount
        Logger.info("queryMsgBoardList():查询成功")
    except Exception as e:
        executeResult = str(e) + "\n" + traceback.format_exc()
        Logger.error("queryMsgBoardList():查询异常:%s" % executeResult)
        response["code"] = "1"
        response["message"] = executeResult
    return JsonResponse(data=response, json_dumps_params={'ensure_ascii': False})

(3)url层路由配置:urls.py

    path("api/msgBoard/queryMsgBoardList", views.queryMsgBoardList, name="queryMsgBoardList"),

2、前端页面开发

前端页面以前用原生JS写过一些,也是面向百度编码的水平。且写出来的页面不是很美观,不如找现成的轮子,又快又好看。

听前端的同事安利了Vue+Element-UI,熟悉了两天,写写简单页面够用了

进入正题:

(1)静态页面开发:msgBoard.vue   列表展示部分:

   <div>
      <el-form>
              <el-form-item>
                <el-row>
                  <el-table :data="msgBoardList" row-class-name="mqRowClass" class="msgBoardListClass">
                    <!-- 折叠 -->
                      <el-table-column type="expand">
                        <template slot-scope="props">
                          <el-form label-position="left" inline class="fold-table-expand">
                            <!-- <el-form-item label="序号">
                              <span>{{ props.row.No }}</span>
                            </el-form-item>
                            <el-form-item label="留言类型">
                              <span>{{ props.row.msgType }}</span>
                            </el-form-item> -->
                            <el-form-item label="楼层">
                              <span>{{ props.row.msgBody }}</span>
                            </el-form-item>
                            <!-- <el-form-item label="提交人">
                              <span>{{ props.row.msgAuthor }}</span>
                            </el-form-item>
                            <el-form-item label="留言时间">
                              <span>{{ props.row.createTime }}</span>
                            </el-form-item> -->
                          </el-form>
                        </template>
                      </el-table-column>
                    <!-- 展示列表 -->
                    <el-table-column  label="ID" min-width="10" align="center">
                      <template scope="scope"> {{ scope.row.msgId }} </template>
                    </el-table-column>
                    <el-table-column  label="留言类型" min-width="18" align="center">
                      <template scope="scope"> {{ scope.row.msgType }} </template>
                    </el-table-column>
                    <el-table-column  label="留言内容" min-width="125" align="center" show-overflow-tooltip="true" class="cellClass">
                      <template scope="scope"> {{ scope.row.msgBody }} </template>
                    </el-table-column>
                    <el-table-column  label="提交人" min-width="15" align="center">
                      <template scope="scope"> {{ scope.row.msgAuthor }} </template>
                    </el-table-column>
                    <el-table-column  label="留言时间" min-width="22" align="center">
                      <template scope="scope"> {{ scope.row.createTime }} </template>
                    </el-table-column>
                    <!-- <el-table-column  label="备注" min-width="18" align="center">
                      <template scope="scope"> {{ scope.row.msgComment }} </template>
                    </el-table-column> -->
                    <el-table-column  label="操作" min-width="20" align="center">
                        <template slot-scope="scope">
                          <el-button type="text" @click="replyMsg(scope.row)">回复</el-button>
                          <!-- <el-button type="text" @click="editCrontabTask(scope.row)">批注 - 开发中</el-button> -->
                        </template>
                    </el-table-column>
                  </el-table>
                </el-row>
              </el-form-item>   
        </el-form>
    </div>

(2)调用后端接口:msgBoard.js

import request from '@/utils/request'
import { MessageBox, Message } from 'element-ui'


export function queryMsgBoardList(data) {
    Message({
        message: "请求已发出,请稍等" || 'Info',
        type: 'Info',
        // duration: 5 * 1000
      })
    return request({
      url: '/msgBoard/queryMsgBoardList',
      method: 'post',
      data
    })
  }

请求是基于request.js发出的,模板中已封装好,修改一下相关的状态码校验即可,不再赘述。

前端开发完成后,cmd敲编译命令,如果代码OK,就能够看到所代码会被webpack自动打包到dist目录下了,至此前端开发完成;

3、前后端绑定:settings.py

(1)贴一些关键配置

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            # 配置Django项目的模板搜索路径
            os.path.join(BASE_DIR, r"vue-admin\dist"),

        ],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

# Add for vuejs  配置一下静态文件的搜索路径
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, r"vue-admin\dist\static"),
]

4、启动服务、访问

(1)启动后端服务:manage.py runserver 0.0.0.0:8080 

 

(2)访问: http://{本地IP}:8080/home 代码没有问题的话,就可以进入首页了;

(3)找到自己所属的菜单,点击即可使用上述开发的功能了

 

posted @ 2020-03-23 11:22  陈月白  阅读(1666)  评论(4编辑  收藏  举报