准备工作
注意:项目整个过程需要从后往前,即先数据库->后端->前端;启动流程也是先启动后端项目,再启动前端项目
前端
开发工具:Visual Studio Code(推荐)、WebStorm
打开cmd,安装Vue脚手架,命令如下:
创建Vue2项目,名为vue-axios
选择Manually select features
进行创建,回车

目前只勾选Router
,回车

选择2.x
,回车

选择如下,回车,等待下载依赖

下载完成后,进入到项目内
安装axios库
安装Element UI库
在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 debug
- return Promise.reject(error)
- }
- )
-
- export default 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);
-
- new Vue({
- router,
- render: function (h) { return h(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 = new VueRouter({
- mode: 'history',
- base: process.env.BASE_URL,
- routes
- })
-
- export default router
打开终端或cmd,输入如下命令启动项目
在浏览器输入http://localhost:8080/
即可打开首页,默认查询全部数据,如下:

添加页面:

编辑页面:

删除页面:

基本的增删改查均已实现,全部采用接口请求的方式进行实现,在开发者工具的网络工具栏下,可以看到前端发送的请求,如下:

以及后端响应数据的预览结果:

后端
开发环境:PyCharm(推荐)、Visual Studio Code
打开cmd,安装flask库,命令如下:
安装flask_cors库,命令如下:
安装pymysql库,命令如下:
创建Python项目,名为python-flask
新建json_response.py
,统一json返回格式
- # 统一的json返回格式
-
- class JsonResponse(object):
-
- def __init__(self, code, msg, data):
- self.code = code
- self.msg = msg
- self.data = data
-
- # 指定一个类的方法为类方法,通常用self来传递当前类的实例--对象,cls传递当前类。
- @classmethod
- def success(cls, code=200, msg='success', data=None):
- return cls(code, msg, data)
-
- @classmethod
- def fail(cls, code=400, msg='fail', data=None):
- return cls(code, msg, data)
-
- def to_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
-
- class JsonFlask(Flask):
- def make_response(self, rv):
- # 视图函数可以直接返回: list、dict、None
- if rv is None or isinstance(rv, (list, dict)):
- rv = JsonResponse.success(rv)
-
- if isinstance(rv, JsonResponse):
- rv = jsonify(rv.to_dict())
-
- return super().make_response(rv)
新建config.py
,数据库操作
- # 数据库操作类
-
- import pymysql
-
- DB_CONFIG = {
- "host": "127.0.0.1",
- "port": 3306,
- "user": "root",
- "passwd": "123456",
- "db": "test",
- "charset": "utf8"
- }
-
- class SQLManager(object):
-
- # 初始化实例方法
- def __init__(self):
- self.conn = None
- self.cursor = None
- self.connect()
-
- # 连接数据库
- def connect(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)
-
- # 查询多条数据
- def get_list(self, sql, args=None):
- self.cursor.execute(sql, args)
- return self.cursor.fetchall()
-
- # 查询单条数据
- def get_one(self, sql, args=None):
- self.cursor.execute(sql, args)
- return self.cursor.fetchone()
-
- # 执行单条SQL语句
- def modify(self, sql, args=None):
- row = self.cursor.execute(sql, args)
- self.conn.commit()
- return row > 0
-
- # 执行多条SQL语句
- def multi_modify(self, sql, args=None):
- rows = self.cursor.executemany(sql, args)
- self.conn.commit()
- return rows > 0
-
- # 关闭数据库cursor和连接
- def close(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"]) # 查询(全部)
- def all():
- result = db.get_list(sql='select * from user')
- return JsonResponse.success(msg='查询成功', data=result)
-
- @app.route("/add", methods=["POST"]) # 添加(单个)
- def add():
- 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"]) # 修改(单个)
- def update():
- data = json.loads(request.data) # 将json字符串转为dict
- if 'id' not in 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"]) # 删除(单个)
- def delete():
- if 'id' not in 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端口,此处设置端口为666
- if __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
- -- ----------------------------
- DROP TABLE IF EXISTS `user`;
- CREATE TABLE `user` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) CHARACTER SET gbk COLLATE gbk_chinese_ci NOT NULL,
- `age` int(11) NOT NULL,
- `sex` varchar(255) CHARACTER SET gbk COLLATE gbk_chinese_ci NOT NULL,
- PRIMARY KEY (`id`) USING BTREE
- ) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = gbk COLLATE = gbk_chinese_ci ROW_FORMAT = Compact;
-
- -- ----------------------------
- -- Records of user
- -- ----------------------------
- INSERT INTO `user` VALUES (1, 'tom', 20, '男');
- INSERT INTO `user` VALUES (2, 'mary', 20, '女');
- INSERT INTO `user` VALUES (3, 'jack', 21, '男');
- INSERT INTO `user` VALUES (5, 'test', 20, '未知');
- INSERT INTO `user` VALUES (8, 'tom', 20, '男');
- INSERT INTO `user` VALUES (9, 'add', 20, '未知');
- INSERT INTO `user` VALUES (10, 'Saly', 11, '女');
-
- SET FOREIGN_KEY_CHECKS = 1;
总结
到此这篇关于如何利用Python+Vue实现简单的前后端分离的文章就介绍到这了,更多相关Python+Vue实现前后端分离内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!