0


Python+Vue实现简单的前后端分离

准备工作

  1. 安装Node环境
  2. 安装Python环境

注意:项目整个过程需要从后往前,即先数据库->后端->前端;启动流程也是先启动后端项目,再启动前端项目

前端

开发工具:Visual Studio Code(推荐)、WebStorm

打开cmd,安装Vue脚手架,命令如下:

npm install -g @vue/cli

创建Vue2项目,名为

vue-axios
vue create vue-axios

选择

Manually select features

进行创建,回车
在这里插入图片描述
目前只勾选

Router

,回车
在这里插入图片描述
选择

2.x

,回车
在这里插入图片描述
选择如下,回车,等待下载依赖
在这里插入图片描述
下载完成后,进入到项目内

cd vue-axios

安装axios库

npm install axios --save

安装Element UI库

npm i element-ui -S

在src下新建utils文件夹,将

request.js

放于src/utils/下,

request.js

是axios的二次封装,如下:

import axios from'axios'const request = axios.create({baseURL:'http://127.0.0.1:666',// 注意!! 这里是全局统一加上了 后端接口前缀 前缀,后端必须进行跨域配置!timeout:5000})// request 拦截器// 可以自请求发送前对请求做一些处理// 比如统一加token,对请求参数统一加密
request.interceptors.request.use(config=>{
    config.headers['Content-Type']='application/json;charset=utf-8';// config.headers['token'] = user.token;  // 设置请求头return config
},error=>{return Promise.reject(error)});// response 拦截器// 可以在接口响应后统一处理结果
request.interceptors.response.use(response=>{let res = response.data;// 如果是返回的文件if(response.config.responseType ==='blob'){return res
        }// 兼容服务端返回的字符串数据if(typeof res ==='string'){
            res = res ?JSON.parse(res): res
        }return res;},error=>{
        console.log('err'+ error)// for debugreturn Promise.reject(error)})exportdefault request

修改main.js,进行注册

import Vue from'vue'import App from'./App.vue'import router from'./router'import request from"@/utils/request"import ElementUI from'element-ui';import'element-ui/lib/theme-chalk/index.css';// 关闭生产模式下的提示
Vue.config.productionTip =false// 设置axios为Vue的原型属性Vue.prototype.$axios = request

Vue.use(ElementUI);newVue({
  router,render:function(h){returnh(App)}}).$mount('#app')

删除多余的组件,如在src/views和src/components下的vue组件;在src/views新建

Home.vue

组件:

<template>
  <div class="home">
    <h1>前后端分离小demo</h1>

    <!-- 表格区域 -->
    <el-table
      :data="table"
      stripe
      :cell-style="{ textAlign: 'center' }"
      :header-cell-style="{ textAlign: 'center' }"
    >
      <el-table-column prop="id" label="ID" width="100" sortable />
      <el-table-column prop="name" label="姓名" />
      <el-table-column prop="age" label="年龄" />
      <el-table-column prop="sex" label="性别" />

      <el-table-column label="操作" width="210">
        <template slot="header">
          <span class="op">操作</span>
          <el-button size="mini" class="add" @click="add" icon="el-icon-plus"
            >添加一条记录</el-button
          >
        </template>
        <template slot-scope="scope">
          <el-button
            type="info"
            size="mini"
            @click="handEdit(scope.$index, scope.row)"
            icon="el-icon-edit"
            round
            >编辑</el-button
          >
          <el-popconfirm
            title="确认删除吗?"
            @confirm="handDelete(scope.$index, scope.row)"
          >
            <el-button
              type="danger"
              size="mini"
              icon="el-icon-delete"
              round
              slot="reference"
              >删除</el-button
            >
          </el-popconfirm>
        </template>
      </el-table-column>
    </el-table>

    <!-- 弹出窗 -->
    <el-dialog
      :title="title"
      :visible="dialogVisible"
      width="30%"
      :before-close="handleClose"
    >
      <el-form
        :model="form"
        status-icon
        :rules="rules"
        ref="form"
        label-width="60px"
      >
        <el-form-item label="姓名" prop="name">
          <el-input v-model="form.name" autocomplete="off" />
        </el-form-item>
        <el-form-item label="年龄" prop="age">
          <el-input
            type="number"
            min="1"
            max="99"
            v-model="form.age"
            autocomplete="off"
          />
        </el-form-item>
        <el-form-item label="性别" prop="sex">
          <el-radio-group v-model="form.sex">
            <el-radio label="男"></el-radio>
            <el-radio label="女"></el-radio>
            <el-radio label="未知"></el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="reset">重置</el-button>
        <el-button type="primary" @click="save">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>

export default {
  name: 'Home',
  data() {
    // 自定义验证规则
    var validateAge = (rule, value, callback) => {
      if (value === '' || value === undefined) {
        callback(new Error('请输入年龄'))
      } else if (isNaN(value)) {
        callback(new Error('请输入数字'))
      } else if (value < 1 || value > 100) {
        callback(new Error('年龄必须在1~100之间'))
      } else {
        callback()
      }
    }
    return {
      table: [],
      dialogVisible: false,
      title: '',
      form: {},
      rules: {
        name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
        age: [{ required: true, validator: validateAge, trigger: 'blur' }],
        sex: [{ required: true, message: '请选择性别', trigger: 'blur' }],
      }
    }
  },
  created() {
    this.init()
  },
  methods: {
    init() {
      this.$axios.get('/all').then(res => {
        console.log(res);
        this.table = res.data
      })
    },
    add() {
      this.dialogVisible = true
      this.title = '添加记录'
      this.form = {}
    },
    handEdit(index, row) {
      this.dialogVisible = true
      this.title = '编辑记录'
      this.form = JSON.parse(JSON.stringify(row))
    },
    handDelete(index, row) {
      let id = JSON.parse(JSON.stringify(row)).id
      this.$axios.delete(`/delete?id=${id}`).then(res => {
        if (res.code == 200) {
          this.$notify.success({
            title: '成功',
            message: res.msg,
            duration: 2000
          })
          this.init()
        } else {
          this.$notify.success({
            title: '失败',
            message: res.msg,
            duration: 2000
          })
        }
      })
    },
    handleClose() {
      this.dialogVisible = false
      this.init()
    },
    reset() {
      let id = undefined
      if ('id' in this.form) {
        id = this.form.id
      }
      this.form = {}
      if (id != undefined) this.form.id = id
    },
    save() {
      this.$refs['form'].validate(valid => {    // 判断是否通过验证
        if (valid) {
          console.log(this.form);
          if ('id' in this.form) {
            // console.log('修改');

            this.$axios.put('/update', this.form).then(res => {
              if (res.code == 200) {
                let _this = this
                this.$notify.success({
                  title: '成功',
                  message: res.msg,
                  duration: 2000,
                  onClose: function () { _this.handleClose() }
                });
              } else {
                this.$notify.error({
                  title: '错误',
                  message: res.msg,
                  duration: 2000
                });
              }
            })

          } else {
            // console.log('添加');

            this.$axios.post('/add', this.form).then(res => {
              if (res.code == 200) {
                let _this = this
                this.$notify.success({
                  title: '成功',
                  message: res.msg,
                  duration: 2000,
                  onClose: function () { _this.handleClose() }
                });
              } else {
                this.$notify.error({
                  title: '错误',
                  message: res.msg,
                  duration: 2000
                });
              }
            })
          }
        }
      })
    }
  }
}
</script>

<style>
h1 {
  text-align: center;
  margin: 50px 0;
}
.el-table {
  width: 60% !important;
  margin: 0 auto;
}
.el-button {
  margin: 0 5px;
}
span.op {
  display: inline-block;
  margin-left: 6px;
}
.el-dialog__body {
  padding-bottom: 0;
}
</style>

修改App.vue,如下:

<template>
  <div id="app">
    <router-view />
  </div>
</template>

<style>
/* 引入外部css */
@import "./assets/css/reset.css";
</style>

其中

reset.css

如下:

*{margin: 0;padding: 0;box-sizing: border-box;}

修改src/router/index.js如下:

import Vue from'vue'import VueRouter from'vue-router'

Vue.use(VueRouter)const routes =[{path:'/',name:'home',component:()=>import('@/views/Home.vue')},]const router =newVueRouter({mode:'history',base: process.env.BASE_URL,
  routes
})exportdefault router

打开终端或cmd,输入如下命令启动项目

npm run serve

在浏览器输入

http://localhost:8080/

即可打开首页,默认查询全部数据,如下:
在这里插入图片描述
添加页面:
在这里插入图片描述
编辑页面:
在这里插入图片描述
删除页面:
在这里插入图片描述
基本的增删改查均已实现,全部采用接口请求的方式进行实现,在开发者工具的网络工具栏下,可以看到前端发送的请求,如下:
在这里插入图片描述
以及后端响应数据的预览结果:
在这里插入图片描述

后端

开发环境:PyCharm(推荐)、Visual Studio Code

打开cmd,安装flask库,命令如下:

pip install flask

安装flask_cors库,命令如下:

pip install flask_cors

安装pymysql库,命令如下:

pip install pymysql

创建Python项目,名为

python-flask

新建

json_response.py

,统一json返回格式

# 统一的json返回格式classJsonResponse(object):def__init__(self, code, msg, data):
        self.code = code
        self.msg = msg
        self.data = data

    # 指定一个类的方法为类方法,通常用self来传递当前类的实例--对象,cls传递当前类。@classmethoddefsuccess(cls, code=200, msg='success', data=None):return cls(code, msg, data)@classmethoddeffail(cls, code=400, msg='fail', data=None):return cls(code, msg, data)defto_dict(self):return{"code": self.code,"msg": self.msg,"data": self.data
        }

新建

json_flask.py

,使flask支持返回JsonResponse对象

from flask import Flask, jsonify

from json_response import JsonResponse

classJsonFlask(Flask):defmake_response(self, rv):# 视图函数可以直接返回: list、dict、Noneif rv isNoneorisinstance(rv,(list,dict)):
            rv = JsonResponse.success(rv)ifisinstance(rv, JsonResponse):
            rv = jsonify(rv.to_dict())returnsuper().make_response(rv)

新建

config.py

,数据库操作

# 数据库操作类import pymysql

DB_CONFIG ={"host":"127.0.0.1","port":3306,"user":"root","passwd":"123456","db":"test","charset":"utf8"}classSQLManager(object):# 初始化实例方法def__init__(self):
        self.conn =None
        self.cursor =None
        self.connect()# 连接数据库defconnect(self):
        self.conn = pymysql.connect(
            host=DB_CONFIG["host"],
            port=DB_CONFIG["port"],
            user=DB_CONFIG["user"],
            passwd=DB_CONFIG["passwd"],
            db=DB_CONFIG["db"],
            charset=DB_CONFIG["charset"])
        self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)# 查询多条数据defget_list(self, sql, args=None):
        self.cursor.execute(sql, args)return self.cursor.fetchall()# 查询单条数据defget_one(self, sql, args=None):
        self.cursor.execute(sql, args)return self.cursor.fetchone()# 执行单条SQL语句defmodify(self, sql, args=None):
        row = self.cursor.execute(sql, args)
        self.conn.commit()return row >0# 执行多条SQL语句defmulti_modify(self, sql, args=None):
        rows = self.cursor.executemany(sql, args)
        self.conn.commit()return rows >0# 关闭数据库cursor和连接defclose(self):
        self.cursor.close()
        self.conn.close()

新建

app.py

,主程序

from flask import request
from flask_cors import*from json_flask import JsonFlask
from json_response import JsonResponse
from config import*import json

# 创建视图应用
app = JsonFlask(__name__)# 解决跨域
CORS(app, supports_credentials=True)

db = SQLManager()# 编写视图函数,绑定路由@app.route("/all", methods=["GET"])# 查询(全部)defall():
    result = db.get_list(sql='select * from user')return JsonResponse.success(msg='查询成功', data=result)@app.route("/add", methods=["POST"])# 添加(单个)defadd():
    data = json.loads(request.data)# 将json字符串转为dict
    isOk = db.modify(sql='insert into user(name,age,sex) values(%s,%s,%s)',
                      args=[data['name'], data['age'], data['sex']])return JsonResponse.success(msg='添加成功')if isOk else JsonResponse.fail(msg='添加失败')@app.route("/update", methods=["PUT"])# 修改(单个)defupdate():
    data = json.loads(request.data)# 将json字符串转为dictif'id'notin data:return JsonResponse.fail(msg='需要传入id')
    isOk = db.modify(sql='update user set name=%s,age=%s,sex=%s where id=%s',
                      args=[data['name'], data['age'], data['sex'], data['id']])return JsonResponse.success(msg='修改成功')if isOk else JsonResponse.fail(msg='修改失败')@app.route("/delete", methods=["DELETE"])# 删除(单个)defdelete():if'id'notin request.args:return JsonResponse.fail(msg='需要传入id')
    isOk = db.modify(sql='delete from user where id=%s', args=[request.args['id']])return JsonResponse.success(msg='删除成功')if isOk else JsonResponse.fail(msg='删除失败')# 运行flask:默认是5000端口,此处设置端口为666if __name__ =='__main__':
    app.run(host="0.0.0.0", port=666, debug=True)

启动项目。

数据库

采用MySQL,由于是小demo,此处设计较简单,数据库名为

test

,表名为

user

,表结构和数据SQL语句如下:

SET NAMES utf8mb4;SET FOREIGN_KEY_CHECKS =0;-- ------------------------------ Table structure for user-- ----------------------------DROPTABLEIFEXISTS`user`;CREATETABLE`user`(`id`int(11)NOTNULLAUTO_INCREMENT,`name`varchar(255)CHARACTERSET gbk COLLATE gbk_chinese_ci NOTNULL,`age`int(11)NOTNULL,`sex`varchar(255)CHARACTERSET gbk COLLATE gbk_chinese_ci NOTNULL,PRIMARYKEY(`id`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=11CHARACTERSET= gbk COLLATE= gbk_chinese_ci ROW_FORMAT = Compact;-- ------------------------------ Records of user-- ----------------------------INSERTINTO`user`VALUES(1,'tom',20,'男');INSERTINTO`user`VALUES(2,'mary',20,'女');INSERTINTO`user`VALUES(3,'jack',21,'男');INSERTINTO`user`VALUES(5,'test',20,'未知');INSERTINTO`user`VALUES(8,'tom',20,'男');INSERTINTO`user`VALUES(9,'add',20,'未知');INSERTINTO`user`VALUES(10,'Saly',11,'女');SET FOREIGN_KEY_CHECKS =1;
标签: python vue mysql

本文转载自: https://blog.csdn.net/qq_45917176/article/details/125421084
版权归原作者 杼蛘 所有, 如有侵权,请联系我们删除。

“Python+Vue实现简单的前后端分离”的评论:

还没有评论