飞哥的海

导航

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>
UserManage.vue

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
usermanage.py(service)
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
usermanage.py(controller)

 

3.在写后端代码时,引发了另一个问题,就是关于函数错误码定义问题。http本身有完善的错误码,而我后端代码也该定义一些合适的错误码。

4.有了用户,当然也该有角色分配。所以接下来会探索角色和用户的联系。sqlalchemy将是下面重点学习内容。当然前端可以刷路由概念了。

 

posted on 2020-08-18 17:34  飞哥的海  阅读(1383)  评论(0编辑  收藏  举报