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將是下面重點學習內容。當然前端可以刷路由概念了。