vue+python前后端MVC的初探
0.继续上次的思路,将持续探索mvc。python的优势是简洁明快,我并不想为了适应mvc模式,而让后端结构看起来极为臃肿。一直在寻找关于mvc的权威书籍。
1.这次前端用添加了用户列表功能。点击下面列表,上面就会同步显示信息,
1.1 vue双向绑定的优势,如果用传统jquery方式,实现这个功能能把人写吐血。
1.2 还尝试了async await语法,这是新版js的特性,等待异步事件。其实会使用await也就理解了promise。
1.3 也使用了vue 的v-if 语法。这也是个美味的语法,很方便。
1.3 我一直认为,学习语言最好的方式,先不求甚解的通读一遍基本语法,然后构思一个项目,随着项目的迭代,语言能力也会随之提高。
<template> <div class="app-container"> <el-form ref="userForm" :model="userData" :rules="rules" status-icon label-width="100px" class="demo-ruleForm"> <el-form-item label="用户ID" prop="id"> <el-input ref="userid" v-model="userData.id" autocomplete="off" disabled></el-input> </el-form-item> <el-form-item label="用户名" prop="username"> <el-input ref="username" v-model="userData.username" autocomplete="off"></el-input> </el-form-item> <el-row> <el-col :span="colWidth"> <el-form-item label="密码" prop="password"> <el-input ref="password" v-model="userData.password" type="password" autocomplete="off"></el-input> </el-form-item> </el-col> <el-col :span="colWidth" v-if="showRePassword()"> <el-form-item label-width=0 prop="rePassword" > <el-input type="password" v-model="userData.rePassword" autocomplete="off"></el-input> </el-form-item> </el-col> </el-row> <el-form-item> <el-button @click="addUser()">新增</el-button> <el-button @click="saveUser()">保存</el-button> </el-form-item> </el-form> <el-table :data="tableData" @row-click="showDetails" style="width: 100%"> <el-table-column prop="id" label="编号" min-width="10%"></el-table-column> <el-table-column prop="username" label="用户名" min-width="30%"></el-table-column> <el-table-column prop="alternativeID" label="用户别名" v-show="true" min-width="50%"></el-table-column> </el-table> </div> </template> <script> import qs from \'qs\' import service from \'../utils/request\' export default { data() { var checkUsername = async (rule, value, callback) => { if (value === \'\') { callback(new Error(\'用户名不可为空\')) } else if (await this.existsUsername(value)){ callback(new Error(\'用户名已占用\')) } else { callback(); } }; var checkPassword = (rule, value, callback) => { if (value === \'\') { callback(new Error(\'请输入密码\')); } else { if (this.userData.rePassword !== \'\') { this.$refs.userForm.validateField(\'rePassword\'); } callback(); } }; var checkRePassword = (rule, value, callback) => { if (value === \'\') { callback(new Error(\'请再次输入密码\')); } else if (value !== this.userData.password) { callback(new Error(\'两次输入密码不一致!\')); } else { callback(); } }; return { status:\'\', colWidth:24, userData:{ id: \'\', username: \'\', password: \'\', rePassword:\'\' }, rules: { username: [ { validator: checkUsername, trigger: \'blur\' } ], password: [ { validator: checkPassword, trigger: \'blur\' } ], rePassword: [ { validator: checkRePassword, trigger: \'blur\' } ] }, tableData: [] }; }, mounted:function(){ this.getUserList() }, methods: { showRePassword() { let canShow = false if ((this.status == \'modify\') || (this.status == \'add\')){ canShow = true } else { canShow = false } return canShow }, getUserList() { let _this = this service({url: \'/userlist\',method: \'get\'}) .then(response => { const { data } = response _this.tableData = data.data console.log(self.tableData) }) .catch(error => { console.log(error) }) }, showDetails(row) { console.log(\'showDetail \'+row) this.userData.id = row.id this.userData.username = row.username this.userData.password = row.password }, saveUser() { let _this = this this.$refs[\'userForm\'].validate((valid) => { if (valid) { service({url: \'/saveuser\',method: \'post\',data: qs.stringify(this.userData)}) .then(response => { const { data } = response alert(\'submit!!!\' +\'\n\'+ data.msg) }) .then(() => { _this.getUserList() _this.colWidth = 24 _this.status = \'\' }) .catch(error => { console.log(error) }) } else { console.log(\'illegad submit!!\'); return false; } }) }, addUser() { this.colWidth = 12 this.status = \'add\' console.log(\'clearForm\') this.$refs[\'userForm\'].resetFields(); }, async existsUsername(value) { let exists = false await service({url: \'/existsusername\',method: \'get\',params: {username: value} }) .then(response => { const { data } = response exists = data.data.exists }) return exists } } } </script>
2.后端代码,在controller层和service层分别添加了usermanage.py.
2.1 比起login代码,我把从外部获取数据的方法全移动到controller层,我考虑,controller层是后端的唯一窗口,禁止其他层从外部获取数据。
2.2 另外我一直在思考是不是把dao层拆出model层,把数据库实体独立看待。而dao层单纯负责增删改查工作。但这么做会不会导致解耦过度。这个问题先延后,看以后代码走向,目前我无法预判。
2.3 还有一个思考,controller层能不能直接访问dao层呢?真是难以抉择。那么换一个问法,controller为什么要访问dao层?当然是前端业务需要,既然有业务需要,什么样的业务简单到没有业务逻辑,只有入库动作?哪怕是简单入库动作,也该做入库前的数据校验。从我目前对dao层的理解,此层应该远离业务逻辑,此层应该更倾向于数据库级。是不是可以这么理解,dao层就相当于数据库查询语言SQL。而model层就相当于数据库的表。如果我的理解是正确的,那么刚才的两个思考也该有答案了。
from flask import jsonify from dao.database import init_db,db_session from dao.operator import Operator import time def userList(): users = db_session.query(Operator).filter(1==1).all() returnData = {\'code\': 0, \'msg\': \'success\', \'data\': Operator.to_json(users)} return jsonify(returnData),200 def existsUsername(username): # time.sleep(3) user = db_session.query(Operator).filter(Operator.username == username).first() if (user == None): return False else: return True def addUser(username,password): if (not existsUsername(username)): oper = Operator(None,username, password) db_session.add(oper) db_session.commit() returnData = {\'code\': 0, \'msg\': \'success\', \'data\': username+\' success\'} return jsonify(returnData),200 else: returnData = {\'code\': 1, \'msg\': \'failed\', \'data\': username+\' faild\'} return jsonify(returnData),200
from flask import Blueprint,jsonify,request import service.usermanage as usermanage bp = Blueprint(\'usermanage_page\',__name__) @bp.route(\'/userlist\') def userlist(): return usermanage.userList() @bp.route(\'/existsusername\') def existsUsername(): username = request.args.get(\'username\', \'\') exists = usermanage.existsUsername(username) returnData = {\'code\': 0, \'msg\': \'success\', \'data\': {\'exists\':exists}} return jsonify(returnData),200 @bp.route(\'/saveuser\', methods=[\'POST\']) def saveUser(): username = request.form[\'username\'] password = request.form[\'password\'] returnData = usermanage.addUser(username,password) return returnData
3.在写后端代码时,引发了另一个问题,就是关于函数错误码定义问题。http本身有完善的错误码,而我后端代码也该定义一些合适的错误码。
4.有了用户,当然也该有角色分配。所以接下来会探索角色和用户的联系。sqlalchemy将是下面重点学习内容。当然前端可以刷路由概念了。