尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Flask+Vue构建干部测评系统:权限、统计与部署全解析

Flask+Vue构建干部测评系统:权限、统计与部署全解析 去年年底接到一个内部需求做一套干部测评系统。说得直白一点就是把过去每年线下纸质打分、人工汇总的民主测评流程搬到线上测评人不用再拿着一叠表格跑来跑去管理员也不用熬夜粘 Excel。技术栈需求写得很宽松就四个字“Python Web”。我第一反应是 Django毕竟它是 Python 里出了名的“全家桶”自带 ORM、Admin、认证开箱即用。但项目真正落地的时候我用的却是 Flask 写后端 API、Vue 写管理端和打分端、PyCharm 做日常开发和接口调试。这篇文章把我当时的完整设计过程、关键代码、统计口径实现以及踩过的坑全部整理出来给正在做测评类、问卷类、投票类系统的朋友一个可复现的参考。1. 项目到底要做什么测评系统的核心需求拆解1.1 测评业务从纸质到线上的完整流程很多人第一次接触“测评系统”会以为这只是一个简单的打分表单。实际上测评类业务的流程链路比普通问卷长不少而且每一环都有状态管理。一个完整的测评流程可以拆成四步。第一步是组织者创建测评项目设定测评对象范围、打分维度、每个维度的权重、测评人分组、各类测评人的权重比例、起止时间。第二步是测评人登录系统看到分配给自己的待办任务打开后是若干个被测评对象每个对象下面按照维度逐项打分最后提交。第三步是项目结束后系统自动统计得出每个对象的分类得分、总分、排名必要时导出报告。第四步是管理者查看结果用于后续的人事参考。这里有一个隐藏需求容易忽略测评人和被测评对象通常是“多对多”的一个测评人往往要给多名干部打分一名干部又会被多名不同类别的人评价。而且不同类别测评人的打分权重完全不同比如领导打分占 40%、同级占 30%、下级占 20%、自我占 10%不能简单把所有分数加起来取平均。这种“分组加权”的统计模型是整个系统最核心的业务逻辑。1.2 角色划分与核心功能清单我把系统拆成了三个角色。系统管理员负责创建项目、维护用户、配置权重、启动和结束测评普通测评人负责接收任务、打分、查看自己的提交记录领导/查看人只读只关注统计结果和排名。为了把所有需求理清楚我列了一张功能清单出来后面就照着它开发用户管理登录、角色区分、测评人类别维护项目配置创建测评项目、设定时间窗口、配置打分维度维度管理默认有“德、能、勤、绩、廉”五类每类可设权重测评对象管理维护干部名单及所属部门任务生成项目发布时按规则自动生成每个测评人的待办任务打分提交限制测评人只能打一次截止后禁止提交自动统计按类别分组、组内求平均、再按类别权重加权求和结果查看对象总分、维度明细、排名这里我想特别提醒一点任务生成这个环节非常关键。系统在项目发布的时候要自动给每个测评人生成一份“任务明细”记录他需要对哪些对象打分。如果项目发布后再临时增减测评对象任务也要同步更新这种关联逻辑是目前最容易出错的地方后面开发时要重点设计。2. 技术选型的实战考量Flask、Django、Vue 和 PyCharm 各自扮演什么角色2.1 为什么最终选 Flask 而不是 Django标题里同时出现了 Flask 和 Django确实容易让人困惑。我先说结论这套系统最终是 Flask 做后端 APIDjango 在选型阶段被我拿来做了详细对比最后被否掉不是因为不好而是因为场景不匹配。我当时的判断标准有三条。第一这套系统是典型的前后端分离结构前端展示交给 Vue后端核心只提供 JSON API用不上 Django 自带的模板引擎和 Admin。第二测评业务的自定义程度非常高任务生成、加权统计、权限隔离都是强业务逻辑比起在 Django 的固定套路上做定制不如用轻量的 Flask 自己拼装。第三团队对 Flask 更熟悉开发效率更高。但 Django 也不是没有优点。它的 ORM 查询能力更成熟Admin 后台在业务初期几乎能当半个管理端用。如果项目要求在单一框架里前后端不分离、快速搭出管理后台我会毫不犹豫选 Django。所以更准确地说这不是谁比谁强的问题而是架构形态决定了框架选型。我还参考了 Django 的 MTV 分层思想来组织 Flask 代码路由层只做参数接收和响应返回业务逻辑层处理计算模型层管数据表映射从分层思路上两者其实是一致的。2.2 前端为什么用 Vue版本怎么定前端我选了 Vue直接原因有三个Vue 的响应式数据绑定非常适合表单类交互场景单文件组件让页面结构清爽打分页、结果页、统计页各自独立维护不打架生态成熟配 Element Plus 组件库表格、表单、弹窗基本不用重复造轮子。我对比过 React但在这个项目里 Vue 的性价比更高。React 的设计哲学是“一切皆 JavaScript”函数式写法更灵活但对团队而言成本也更高Vue 的模板语法更接近传统 HTML做这类中后台系统上手极快。版本方面我用的 Vue 3 Vite Element Plus不建议再开新项目用 Vue 2 了Vue 3 的 Composition API 写这种多状态交互页面会舒服很多。2.3 PyCharm 在整个开发流里的位置开发工具我用的是 PyCharm Professional。有人觉得 IDE 无所谓但我坚持在类似项目里用 PyCharm因为它的 Flask 调试支持确实省心可以直接创建 Flask Run Configuration打断点调试请求处理过程配合内置的数据库工具还能直接看表结构和查询结果。社区版免费但少了数据库导航、HTTP Client、专业前端支持这些能力。如果预算有限社区版也能开发只是需要额外装插件弥补体验稍打折扣。我的建议是长期做 Python Web 开发专业版值得投入只做这一个项目社区版加 VSCode 也完全够用。3. 从零搭建项目的完整实操记录3.1 开发环境配置PyCharm 虚拟环境 项目依赖第一步是在 PyCharm 里新建 Flask 项目。我一般习惯先把虚拟环境建好再装依赖避免把全局 Python 环境搞乱。用虚拟环境的原因很简单项目 A 要用 Flask 2.x项目 B 要用 Django 4.x依赖版本互相干扰会很痛苦。建好虚拟环境后在终端依次安装后端依赖pip install flask flask-sqlalchemy flask-cors PyJWT pymysql这几个库分别负责 Web 服务、ORM、跨域、JWT 认证和 MySQL 驱动。开发阶段我用 SQLite 当数据库连安装和配置都省了一键启动。生产环境再把连接串换成 MySQLSQLAlchemy 对底层数据库切换是透明的。后端项目结构我整理成下面这样每个模块职责单一方便后面加功能backend/ ├── app.py # Flask 入口注册路由 ├── config.py # 配置类包含数据库连接、密钥 ├── models.py # SQLAlchemy 模型定义 ├── auth.py # 登录、JWT 校验、权限装饰器 ├── api/ │ ├── project_api.py # 项目管理接口 │ ├── task_api.py # 任务查询与打分提交接口 │ └── stats_api.py # 统计结果接口 └── requirements.txt3.2 数据库表设计任务与分数分离是关键做好测评系统表结构设计是命脉。我第一次设计时把所有字段塞进一张记录表结果状态管理绕来绕去把自己绕晕了。后来重新拆成五张表才算把整个业务理顺。用户表包含登录凭证、角色和测评人类别项目表记录测评活动的基本信息和时间窗口维度表存“德能勤绩廉”这类打分项每项一个权重对象表存被测评干部清单任务表记录“谁给谁打分”的待办关系分数表存每个任务下每个维度的最终得分。核心逻辑在任务表和分数表。任务表体现的是“一件事情”分数表体现的是“这件事的明细结果”。为什么不合并因为测评人打开页面后要先展示对象列表如果只有一个分数表查询时还得聚合再判断哪些打了、哪些没打。有了任务表一个测评人有多少条待办一条 SQL 就能查出来任务状态独立管理提交时再往分数表写明细逻辑非常清晰。核心模型代码大致长这样from flask_sqlalchemy import SQLAlchemy from datetime import datetime db SQLAlchemy() class User(db.Model): __tablename__ user id db.Column(db.Integer, primary_keyTrue) username db.Column(db.String(64), uniqueTrue, nullableFalse) password_hash db.Column(db.String(128), nullableFalse) real_name db.Column(db.String(64), nullableFalse) role db.Column(db.String(16), defaultuser) # admin / user evaluator_type db.Column(db.String(16), defaultpeer) # leader / peer / subordinate / self department db.Column(db.String(128), default) class Project(db.Model): __tablename__ project id db.Column(db.Integer, primary_keyTrue) name db.Column(db.String(128), nullableFalse) status db.Column(db.String(16), defaultdraft) # draft / published / finished start_time db.Column(db.DateTime, nullableTrue) end_time db.Column(db.DateTime, nullableTrue) type_weights db.Column(db.Text, default{leader: 0.4, peer: 0.3, subordinate: 0.2, self: 0.1}) created_at db.Column(db.DateTime, defaultdatetime.now) class Dimension(db.Model): __tablename__ dimension id db.Column(db.Integer, primary_keyTrue) project_id db.Column(db.Integer, db.ForeignKey(project.id)) name db.Column(db.String(32), nullableFalse) # 德、能、勤、绩、廉 weight db.Column(db.Float, default1.0) # 维度权重 sort_order db.Column(db.Integer, default0) class Target(db.Model): __tablename__ target id db.Column(db.Integer, primary_keyTrue) project_id db.Column(db.Integer, db.ForeignKey(project.id)) name db.Column(db.String(64), nullableFalse) department db.Column(db.String(128), default) position db.Column(db.String(64), default) class Task(db.Model): __tablename__ task id db.Column(db.Integer, primary_keyTrue) project_id db.Column(db.Integer, db.ForeignKey(project.id)) evaluator_id db.Column(db.Integer, db.ForeignKey(user.id)) target_id db.Column(db.Integer, db.ForeignKey(target.id)) status db.Column(db.String(16), defaulttodo) # todo / done submit_time db.Column(db.DateTime, nullableTrue) class Score(db.Model): __tablename__ score id db.Column(db.Integer, primary_keyTrue) task_id db.Column(db.Integer, db.ForeignKey(task.id)) dimension_id db.Column(db.Integer, db.ForeignKey(dimension.id)) score db.Column(db.Float, nullableFalse)需要注意type_weights 我直接以 JSON 字符串存在项目表里。虽然这不是最“范式化”的做法但从业务角度来说每个测评项目都可能配置一套独立的测评人权重把它挂在项目上是最自然的改权重也不影响历史项目。3.3 登录、JWT 认证与权限控制实现登录是系统的入口我采用 JWT 方案。用户在登录接口提交用户名密码后端验证通过后签发一个有效期为 7 天的 token前端存到 localStorage每次请求在 header 里带上。JWT 的好处是后端无状态不用存 session多机部署也方便。登录接口实现from flask import Flask, request, jsonify, g from werkzeug.security import check_password_hash import jwt from datetime import datetime, timedelta from functools import wraps app Flask(__name__) app.config[SECRET_KEY] your-secret-key-change-in-production app.route(/api/auth/login, methods[POST]) def login(): data request.get_json() user User.query.filter_by(usernamedata.get(username)).first() if user and check_password_hash(user.password_hash, data.get(password)): token jwt.encode( { user_id: user.id, exp: datetime.utcnow() timedelta(days7) }, app.config[SECRET_KEY], algorithmHS256 ) return jsonify({ code: 0, token: token, user: { id: user.id, real_name: user.real_name, role: user.role, evaluator_type: user.evaluator_type } }) return jsonify({code: 1, msg: 用户名或密码错误}), 401权限装饰器是这套系统的安全底座所有需要登录的接口都要挂上。我在装饰器里解析 token把当前用户塞进 Flask 的 g 对象后续处理函数直接读 g.user 就能拿到当前用户信息不用每个接口重复解析 token。def login_required(f): wraps(f) def wrapper(*args, **kwargs): token request.headers.get(Authorization, ).replace(Bearer , ) try: payload jwt.decode(token, app.config[SECRET_KEY], algorithms[HS256]) user User.query.get(payload[user_id]) if not user: raise Exception(user not exists) g.user user except Exception: return jsonify({code: 401, msg: 未登录或登录已过期}), 401 return f(*args, **kwargs) return wrapper这里踩过一个坑JWT 的 exp 时间是 UTC 时间如果客户端和服务器时区不一致用户会突然被提示“登录已过期”。后来我把过期时间统一换算同时在前端 axios 拦截器里判断 401 状态码做跳转登录处理问题才彻底解决。3.4 打分提交与防重复设计打分接口是最需要谨慎的。我做过一次技术评审发现如果只在前端判断“任务是否已提交”用户打开两个页面同时提交后端会收到两次请求最终导致数据库里出现重复分数。所以后端的防重复校验必须做不能只靠前端限制。提交打分接口的关键逻辑根据 task_id 查出任务判断任务的 evaluator_id 是否等于当前登录用户判断任务状态是否已经是 done判断当前时间是否超过项目截止时间全部通过之后先删除该任务下的旧分数幂等设计再批量插入新分数最后把 task 状态改为 done。用“先删旧数据再插入新数据”的方式是为了保证接口的幂等性。哪怕前端重试请求执行结果也是一样的不会产生脏数据。相关代码大约是app.route(/api/tasks/int:task_id/score, methods[POST]) login_required def submit_score(task_id): task Task.query.get(task_id) if not task or task.evaluator_id ! g.user.id: return jsonify({code: 403, msg: 无权操作该任务}), 403 if task.status done: return jsonify({code: 400, msg: 该任务已提交不能重复打分}), 400 project Project.query.get(task.project_id) if project.status finished or ( project.end_time and datetime.now() project.end_time ): return jsonify({code: 400, msg: 测评已结束无法提交}), 400 data request.get_json() scores data.get(scores, {}) # 幂等处理先删除旧分数再插入新分数 Score.query.filter_by(task_idtask.id).delete() for dim_id, score_value in scores.items(): db.session.add(Score(task_idtask.id, dimension_idint(dim_id), scorefloat(score_value))) task.status done task.submit_time datetime.now() db.session.commit() return jsonify({code: 0, msg: 提交成功})3.5 统计模块分组平均加权重计算的完整实现统计模块是整个系统的价值核心也是最容易算错的地方。我先把计算口径确认清楚每个测评对象在每个维度下的最终得分不是所有打分的简单平均而是“先按测评人类别分组求平均分再把各类别平均分按类别权重加权求和”。然后用所有维度的最终得分乘以维度权重汇总出总分。举个例子某干部“德”这个维度领导打分 95 分同级打分 85 分下级打分 80 分。如果三类权重是 0.4、0.3、0.3那“德”的最终得分就是 95×0.4 85×0.3 80×0.3 87.5。如果直接四个数字取平均结果会偏离实际权重意愿。这个口径一定在开发前和业务确认好不然等系统上线再改统计逻辑所有历史数据都会受影响。统计接口的实现我写成了独立函数方便以后扩展历史数据重算app.route(/api/projects/int:project_id/stats, methods[GET]) login_required def project_stats(project_id): project Project.query.get_or_404(project_id) targets Target.query.filter_by(project_idproject_id).all() dimensions Dimension.query.filter_by(project_idproject_id).order_by(Dimension.sort_order).all() type_weights json.loads(project.type_weights or {}) result [] for target in targets: total_score 0 dim_scores {} for dim in dimensions: # 查出该对象在该维度下的所有分数并关联到测评人类别 rows ( db.session.query(Score.score, User.evaluator_type) .join(Task, Score.task_id Task.id) .join(User, Task.evaluator_id User.id) .filter(Task.target_id target.id) .filter(Task.status done) .filter(Score.dimension_id dim.id) .all() ) # 按测评人类别分组求平均 group_scores {} for score_value, etype in rows: group_scores.setdefault(etype, []).append(score_value) final_dim_score 0.0 for etype, score_list in group_scores.items(): avg_score sum(score_list) / len(score_list) final_dim_score avg_score * type_weights.get(etype, 0) final_dim_score round(final_dim_score, 2) dim_scores[dim.name] final_dim_score total_score final_dim_score * dim.weight result.append({ target_id: target.id, target_name: target.name, department: target.department, dim_scores: dim_scores, total_score: round(total_score, 2) }) result.sort(keylambda x: x[total_score], reverseTrue) return jsonify({code: 0, data: result})统计逻辑里有个容易被忽略的细节某个测评人如果漏打、或者某类测评人数量为 0那该类别直接跳过不参与加权。按实际经验这种情况很常见毕竟民主测评总有人忘记打分。统计时对“缺失类别”的处理会直接影响最终排名最好在需求阶段就明确“缺类别的对象是否还能参与排名”避免后期扯皮。3.6 前端 Vue 项目的搭建与核心页面前端我用 Vite 创建 Vue 3 项目npm create vitelatest frontend -- --template vue cd frontend npm install axios element-plus vue-router4开发阶段最麻烦的是跨域。之前不懂事直接在 Flask 里配 flask-cors 放行所有源开发时倒是通了但生产环境有安全隐患。后来我改成开发环境前端跑 5173 端口Vite 配置代理把 /api 请求转发到后端 5000 端口浏览器视角里始终是同一个源后端也不再需要开放跨域。Vite 代理配置如下// vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { proxy: { /api: { target: http://localhost:5000, changeOrigin: true } } } })axios 统一封装我也贴一下。把 token 注入和 401 拦截统一处理后面写业务页面就不用重复关心这些琐事。// src/api/index.js import axios from axios const service axios.create({ baseURL: /api, timeout: 10000 }) service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers.Authorization Bearer ${token} } return config }) service.interceptors.response.use( response response.data, error { if (error.response error.response.status 401) { localStorage.removeItem(token) window.location.href /login } return Promise.reject(error) } ) export default service前端最核心的页面是打分页。逻辑是进入待办列表时循环调接口把每个任务的维度和历史分数一并加载用户在表单里修改分数提交时把整个对象的分数一次性提交。页面状态要区分“未开始、编辑中、已提交”并对已提交的任务锁定表单防止误改。具体到 Vue 3 的 Composition API核心代码思路是这样script setup import { ref, onMounted } from vue import api from /api const tasks ref([]) onMounted(async () { const res await api.get(/tasks) tasks.value res.data.filter(t t.project_status published) }) async function submitScores(task) { if (task.status done) return await api.post(/tasks/${task.task_id}/score, { scores: task.scores }) task.status done } /script这里的 scores 是一个对象键是 dimension_id值是分数。页面上的每个输入框都直接绑定 task.scores[dim.id]实现双向同步不需要额外写赋值逻辑Vue 的响应式在这里确实帮我省了不少事。4. 开发过程中最常见的问题与排查技巧4.1 跨域、代理和部署相关的坑我在开发阶段遇到过“接口直接能通、打包部署后就 404”的问题。原因是开发时 Vite 代理只作用于 dev server前端打包成静态文件后所有接口地址都变成了走 nginx 的 80 端口。如果 nginx 只配置了静态文件目录而没有配置反向代理/api 请求全部 404。解决办法是在 nginx 配置里增加如下一段location /api/ { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }注意 proxy_pass 后面如果有路径行为会不一样容易把人绕晕。我这里直接用不带路径的写法保证 /api 原样转发给后端。后端生产环境我用 gunicorn 起服务pip install gunicorn gunicorn -w 4 -b 127.0.0.1:5000 app:app线上部署的最大心得是前端打包、nginx 静态目录、后端反向代理这三层配置一定要提前用部署文档固定下来别靠记忆。我后来把 nginx 配置提交到了仓库的 deploy 目录换机器部署直接复制省了很多查资料的功夫。4.2 中文乱码问题模拟数据导入后页面显示中文全部变成问号典型的 MySQL 字符集问题。数据库连接串里指定 utf8mb4 可以解决大部分情况SQLALCHEMY_DATABASE_URI mysqlpymysql://root:passwordlocalhost/eval_db?charsetutf8mb4同时数据库表本身的字符集也要对。SQLAlchemy 建表时默认继承数据库配置但如果数据库实例创建的时候没指定 utf8mb4后面建出来的表也可能是 latin1。最省事的办法是建库时就执行CREATE DATABASE eval_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;4.3 重复提交与并发问题有段时间测试反馈“偶尔提交两次”。排查后发现是测评人网络慢双击提交按钮产生了并发请求。后端虽然做了 task.status 的判断但两个请求同时进来都读到 status 为 todo就会同时进入写流程导致重复数据。解决办法是在任务更新时加乐观锁条件更新任务状态时多带一个状态条件updated Task.query.filter_by(idtask.id, statustodo).update({status: done})如果 updated 返回 0说明任务已经被其他请求更新过直接返回“重复提交”。这种基于条件更新的做法简单有效不需要引入分布式锁。4.4 统计结果不准的排查思路统计接口上线后业务方反馈某些人的总分和手动 Excel 算不一致。我排查后发现三个原因第一有测评人提交了空白分数前端把所有维度默认初始化为 0后端把这些 0 也当成有效分数统计了第二项目截止后管理员手动调整了权重导致历史数据重算口径变了第三有个测试账号在任务生成前就已经登录没有刷新任务列表以为自己提交了实际后端根本没有他的任务记录。针对第一个问题我在后端校验分数不能为 0且必须在规定档位范围内。针对第二个问题权重一旦项目发布就不允许修改必须新增版本。第三个问题则是前端的任务列表缓存策略问题我改成每次进入页面强制刷新任务列表不读本地缓存。把这三个问题修完后统计结果才和 Excel 对上了。4.5 PyCharm 环境配置的常见问题用 PyCharm 跑 Flask 项目时最容易踩的坑是解释器选错。打开新项目时如果选了默认的全局解释器而不是项目里的 venv会导致安装了依赖也没法 import。解决方法是在 Settings 的 Python Interpreter 里把解释器路径指向项目的 venv。还有一个坑直接点运行按钮启动 Flask有时会走 PyCharm 默认的 Flask 模板工程配置导致路由加载不全。我的做法是坚持用命令行方式启动先启动 venv 里的终端再跑python app.py由我完全控制启动行为。PyCharm 只作为代码编辑和调试工具使用。5. 系统上线之后的扩展方向与个人总结5.1 从最小可用到完整业务的演进空间当前版本已经能跑通完整测评流程但如果要长期用建议继续扩展几个模块。Excel 导入导出是刚需项目发布前需要批量导入干部名单、测评人名单项目结束后需要导出报表归档。刚开始做的时候图省事用了手动逐条添加被业务方批评过。后来接入了 openpyxl 做批量导入几百人的名单几分钟搞定才算真正可用。数据可视化也是一个重要的加分项。统计结果如果只用表格展示人眼很难快速识别排名波动。可以接入 ECharts在结果页画雷达图展示每个干部在“德能勤绩廉”维度的能力覆盖情况绩效对比也直观很多。隐私保护这块也值得说明。测评系统天然要求匿名但技术上的匿名和业务上的匿名是两回事。系统后台可以记录测评人身份用于任务状态管理但在结果展示层必须严格屏蔽单个测评人的分数。任何查询接口都不能返回“谁给谁打了多少分”的数据粒度。5.2 对这套系统整体架构的复盘体会做完整套系统我自己最大的收获是干部测评这类业务系统的技术难点不在框架而在业务模型的边界。框架选型只决定了开发效率的下限而权限隔离、统计口径、数据一致性这些设计才真正决定系统能不能稳定上线。如果让我重新做一次我会在项目启动前花更多时间确认统计口径把“某类测评人缺失怎么办”“权重能否中途改”“项目结束后还能不能补交”这三个问题问清楚。这些业务决策一旦定错了返工成本远超写代码本身。5.3 一个值得提前做的小工具造数脚本最后分享一个我后悔没早点做的东西测试数据生成脚本。开发统计接口的时候我是靠手工在数据库里插了几条数据测试完全没法验证大数据量下的统计是否准确。后来写了一个 Python 脚本自动生成 50 个测评人、20 个对象、5 个维度、每人 20 个对象模拟出几千条打分记录然后和用 Excel 手算的期望值对比。这一步帮我发现了统计代码里权重解析的一个隐蔽 bug如果没有造数脚本这个 bug 大概率会带着错误统计上线。# scripts/mock_data.py 简化版 from app import app from models import db, User, Project, Target, Task, Dimension, Score import random with app.app_context(): db.drop_all() db.create_all() # 建项目 p Project(name2024年度民主测评, statuspublished) db.session.add(p) db.session.flush() # 建维度 for name in [德, 能, 勤, 绩, 廉]: db.session.add(Dimension(project_idp.id, namename, weight1.0)) # 建用户和对象、任务、分数 # 具体的循环插入逻辑这里省略核心是批量造数并随机给分 db.session.commit()写造数脚本不需要花太多时间但它的价值非常高。每次修改统计逻辑、调整表结构之后跑一遍造数脚本把所有数据清空重新生成配合期望值校验就能快速回归测试整个核心链路。做这类数据敏感业务系统我非常建议你也这样做。
返回列表