经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python » 查看文章
如何利用Python+Vue实现简单的前后端分离
来源:jb51  时间:2022/7/25 15:26:33  对本文有异议

准备工作

  • 安装Node环境
  • 安装Python环境

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

前端

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

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

  1. npm install -g @vue/cli

创建Vue2项目,名为vue-axios

  1. vue create vue-axios

选择Manually select features进行创建,回车

目前只勾选Router,回车

选择2.x,回车

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

下载完成后,进入到项目内

  1. cd vue-axios

安装axios库

  1. npm install axios --save

安装Element UI库

  1. npm i element-ui -S

在src下新建utils文件夹,将request.js放于src/utils/下,request.js是axios的二次封装,如下:

  1. import axios from 'axios'
  2.  
  3. const request = axios.create({
  4. baseURL: 'http://127.0.0.1:666', // 注意!! 这里是全局统一加上了 后端接口前缀 前缀,后端必须进行跨域配置!
  5. timeout: 5000
  6. })
  7.  
  8. // request 拦截器
  9. // 可以自请求发送前对请求做一些处理
  10. // 比如统一加token,对请求参数统一加密
  11. request.interceptors.request.use(config => {
  12. config.headers['Content-Type'] = 'application/json;charset=utf-8';
  13.  
  14. // config.headers['token'] = user.token; // 设置请求头
  15.  
  16. return config
  17. }, error => {
  18. return Promise.reject(error)
  19. });
  20.  
  21. // response 拦截器
  22. // 可以在接口响应后统一处理结果
  23. request.interceptors.response.use(
  24. response => {
  25. let res = response.data;
  26. // 如果是返回的文件
  27. if (response.config.responseType === 'blob') {
  28. return res
  29. }
  30. // 兼容服务端返回的字符串数据
  31. if (typeof res === 'string') {
  32. res = res ? JSON.parse(res) : res
  33. }
  34. return res;
  35. },
  36. error => {
  37. console.log('err' + error) // for debug
  38. return Promise.reject(error)
  39. }
  40. )
  41.  
  42. export default request

修改main.js,进行注册

  1. import Vue from 'vue'
  2. import App from './App.vue'
  3. import router from './router'
  4. import request from "@/utils/request"
  5. import ElementUI from 'element-ui';
  6. import 'element-ui/lib/theme-chalk/index.css';
  7.  
  8. // 关闭生产模式下的提示
  9. Vue.config.productionTip = false
  10.  
  11. // 设置axios为Vue的原型属性
  12. Vue.prototype.$axios = request
  13.  
  14. Vue.use(ElementUI);
  15.  
  16. new Vue({
  17. router,
  18. render: function (h) { return h(App) }
  19. }).$mount('#app')

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

  1. <template>
  2. <div class="home">
  3. <h1>前后端分离小demo</h1>
  4.  
  5. <!-- 表格区域 -->
  6. <el-table
  7. :data="table"
  8. stripe
  9. :cell-style="{ textAlign: 'center' }"
  10. :header-cell-style="{ textAlign: 'center' }"
  11. >
  12. <el-table-column prop="id" label="ID" width="100" sortable />
  13. <el-table-column prop="name" label="姓名" />
  14. <el-table-column prop="age" label="年龄" />
  15. <el-table-column prop="sex" label="性别" />
  16.  
  17. <el-table-column label="操作" width="210">
  18. <template slot="header">
  19. <span class="op">操作</span>
  20. <el-button size="mini" class="add" @click="add" icon="el-icon-plus"
  21. >添加一条记录</el-button
  22. >
  23. </template>
  24. <template slot-scope="scope">
  25. <el-button
  26. type="info"
  27. size="mini"
  28. @click="handEdit(scope.$index, scope.row)"
  29. icon="el-icon-edit"
  30. round
  31. >编辑</el-button
  32. >
  33. <el-popconfirm
  34. title="确认删除吗?"
  35. @confirm="handDelete(scope.$index, scope.row)"
  36. >
  37. <el-button
  38. type="danger"
  39. size="mini"
  40. icon="el-icon-delete"
  41. round
  42. slot="reference"
  43. >删除</el-button
  44. >
  45. </el-popconfirm>
  46. </template>
  47. </el-table-column>
  48. </el-table>
  49.  
  50. <!-- 弹出窗 -->
  51. <el-dialog
  52. :title="title"
  53. :visible="dialogVisible"
  54. width="30%"
  55. :before-close="handleClose"
  56. >
  57. <el-form
  58. :model="form"
  59. status-icon
  60. :rules="rules"
  61. ref="form"
  62. label-width="60px"
  63. >
  64. <el-form-item label="姓名" prop="name">
  65. <el-input v-model="form.name" autocomplete="off" />
  66. </el-form-item>
  67. <el-form-item label="年龄" prop="age">
  68. <el-input
  69. type="number"
  70. min="1"
  71. max="99"
  72. v-model="form.age"
  73. autocomplete="off"
  74. />
  75. </el-form-item>
  76. <el-form-item label="性别" prop="sex">
  77. <el-radio-group v-model="form.sex">
  78. <el-radio label="男"></el-radio>
  79. <el-radio label="女"></el-radio>
  80. <el-radio label="未知"></el-radio>
  81. </el-radio-group>
  82. </el-form-item>
  83. </el-form>
  84. <span slot="footer" class="dialog-footer">
  85. <el-button @click="reset">重置</el-button>
  86. <el-button type="primary" @click="save">确 定</el-button>
  87. </span>
  88. </el-dialog>
  89. </div>
  90. </template>
  91.  
  92. <script>
  93.  
  94. export default {
  95. name: 'Home',
  96. data() {
  97. // 自定义验证规则
  98. var validateAge = (rule, value, callback) => {
  99. if (value === '' || value === undefined) {
  100. callback(new Error('请输入年龄'))
  101. } else if (isNaN(value)) {
  102. callback(new Error('请输入数字'))
  103. } else if (value < 1 || value > 100) {
  104. callback(new Error('年龄必须在1~100之间'))
  105. } else {
  106. callback()
  107. }
  108. }
  109. return {
  110. table: [],
  111. dialogVisible: false,
  112. title: '',
  113. form: {},
  114. rules: {
  115. name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
  116. age: [{ required: true, validator: validateAge, trigger: 'blur' }],
  117. sex: [{ required: true, message: '请选择性别', trigger: 'blur' }],
  118. }
  119. }
  120. },
  121. created() {
  122. this.init()
  123. },
  124. methods: {
  125. init() {
  126. this.$axios.get('/all').then(res => {
  127. console.log(res);
  128. this.table = res.data
  129. })
  130. },
  131. add() {
  132. this.dialogVisible = true
  133. this.title = '添加记录'
  134. this.form = {}
  135. },
  136. handEdit(index, row) {
  137. this.dialogVisible = true
  138. this.title = '编辑记录'
  139. this.form = JSON.parse(JSON.stringify(row))
  140. },
  141. handDelete(index, row) {
  142. let id = JSON.parse(JSON.stringify(row)).id
  143. this.$axios.delete(`/delete?id=${id}`).then(res => {
  144. if (res.code == 200) {
  145. this.$notify.success({
  146. title: '成功',
  147. message: res.msg,
  148. duration: 2000
  149. })
  150. this.init()
  151. } else {
  152. this.$notify.success({
  153. title: '失败',
  154. message: res.msg,
  155. duration: 2000
  156. })
  157. }
  158. })
  159. },
  160. handleClose() {
  161. this.dialogVisible = false
  162. this.init()
  163. },
  164. reset() {
  165. let id = undefined
  166. if ('id' in this.form) {
  167. id = this.form.id
  168. }
  169. this.form = {}
  170. if (id != undefined) this.form.id = id
  171. },
  172. save() {
  173. this.$refs['form'].validate(valid => { // 判断是否通过验证
  174. if (valid) {
  175. console.log(this.form);
  176. if ('id' in this.form) {
  177. // console.log('修改');
  178.  
  179. this.$axios.put('/update', this.form).then(res => {
  180. if (res.code == 200) {
  181. let _this = this
  182. this.$notify.success({
  183. title: '成功',
  184. message: res.msg,
  185. duration: 2000,
  186. onClose: function () { _this.handleClose() }
  187. });
  188. } else {
  189. this.$notify.error({
  190. title: '错误',
  191. message: res.msg,
  192. duration: 2000
  193. });
  194. }
  195. })
  196.  
  197. } else {
  198. // console.log('添加');
  199.  
  200. this.$axios.post('/add', this.form).then(res => {
  201. if (res.code == 200) {
  202. let _this = this
  203. this.$notify.success({
  204. title: '成功',
  205. message: res.msg,
  206. duration: 2000,
  207. onClose: function () { _this.handleClose() }
  208. });
  209. } else {
  210. this.$notify.error({
  211. title: '错误',
  212. message: res.msg,
  213. duration: 2000
  214. });
  215. }
  216. })
  217. }
  218. }
  219. })
  220. }
  221. }
  222. }
  223. </script>
  224.  
  225. <style>
  226. h1 {
  227. text-align: center;
  228. margin: 50px 0;
  229. }
  230. .el-table {
  231. width: 60% !important;
  232. margin: 0 auto;
  233. }
  234. .el-button {
  235. margin: 0 5px;
  236. }
  237. span.op {
  238. display: inline-block;
  239. margin-left: 6px;
  240. }
  241. .el-dialog__body {
  242. padding-bottom: 0;
  243. }
  244. </style>

修改App.vue,如下:

  1. <template>
  2. <div id="app">
  3. <router-view />
  4. </div>
  5. </template>
  6.  
  7. <style>
  8. /* 引入外部css */
  9. @import "./assets/css/reset.css";
  10. </style>

其中reset.css如下:

  1. * {
  2. margin: 0;
  3. padding: 0;
  4. box-sizing: border-box;
  5. }

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

  1. import Vue from 'vue'
  2. import VueRouter from 'vue-router'
  3.  
  4. Vue.use(VueRouter)
  5.  
  6. const routes = [
  7. {
  8. path: '/',
  9. name: 'home',
  10. component: () => import('@/views/Home.vue')
  11. },
  12. ]
  13.  
  14. const router = new VueRouter({
  15. mode: 'history',
  16. base: process.env.BASE_URL,
  17. routes
  18. })
  19.  
  20. export default router

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

  1. npm run serve

在浏览器输入http://localhost:8080/即可打开首页,默认查询全部数据,如下:

添加页面:

编辑页面:

删除页面:

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

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

后端

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

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

  1. pip install flask

安装flask_cors库,命令如下:

  1. pip install flask_cors

安装pymysql库,命令如下:

  1. pip install pymysql

创建Python项目,名为python-flask

新建json_response.py,统一json返回格式

  1. # 统一的json返回格式
  2.  
  3. class JsonResponse(object):
  4.  
  5. def __init__(self, code, msg, data):
  6. self.code = code
  7. self.msg = msg
  8. self.data = data
  9.  
  10. # 指定一个类的方法为类方法,通常用self来传递当前类的实例--对象,cls传递当前类。
  11. @classmethod
  12. def success(cls, code=200, msg='success', data=None):
  13. return cls(code, msg, data)
  14.  
  15. @classmethod
  16. def fail(cls, code=400, msg='fail', data=None):
  17. return cls(code, msg, data)
  18.  
  19. def to_dict(self):
  20. return {
  21. "code": self.code,
  22. "msg": self.msg,
  23. "data": self.data
  24. }

新建json_flask.py,使flask支持返回JsonResponse对象

  1. from flask import Flask, jsonify
  2.  
  3. from json_response import JsonResponse
  4.  
  5. class JsonFlask(Flask):
  6. def make_response(self, rv):
  7. # 视图函数可以直接返回: list、dict、None
  8. if rv is None or isinstance(rv, (list, dict)):
  9. rv = JsonResponse.success(rv)
  10.  
  11. if isinstance(rv, JsonResponse):
  12. rv = jsonify(rv.to_dict())
  13.  
  14. return super().make_response(rv)

新建config.py,数据库操作

  1. # 数据库操作类
  2.  
  3. import pymysql
  4.  
  5. DB_CONFIG = {
  6. "host": "127.0.0.1",
  7. "port": 3306,
  8. "user": "root",
  9. "passwd": "123456",
  10. "db": "test",
  11. "charset": "utf8"
  12. }
  13.  
  14. class SQLManager(object):
  15.  
  16. # 初始化实例方法
  17. def __init__(self):
  18. self.conn = None
  19. self.cursor = None
  20. self.connect()
  21.  
  22. # 连接数据库
  23. def connect(self):
  24. self.conn = pymysql.connect(
  25. host=DB_CONFIG["host"],
  26. port=DB_CONFIG["port"],
  27. user=DB_CONFIG["user"],
  28. passwd=DB_CONFIG["passwd"],
  29. db=DB_CONFIG["db"],
  30. charset=DB_CONFIG["charset"]
  31. )
  32. self.cursor = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
  33.  
  34. # 查询多条数据
  35. def get_list(self, sql, args=None):
  36. self.cursor.execute(sql, args)
  37. return self.cursor.fetchall()
  38.  
  39. # 查询单条数据
  40. def get_one(self, sql, args=None):
  41. self.cursor.execute(sql, args)
  42. return self.cursor.fetchone()
  43.  
  44. # 执行单条SQL语句
  45. def modify(self, sql, args=None):
  46. row = self.cursor.execute(sql, args)
  47. self.conn.commit()
  48. return row > 0
  49.  
  50. # 执行多条SQL语句
  51. def multi_modify(self, sql, args=None):
  52. rows = self.cursor.executemany(sql, args)
  53. self.conn.commit()
  54. return rows > 0
  55.  
  56. # 关闭数据库cursor和连接
  57. def close(self):
  58. self.cursor.close()
  59. self.conn.close()

新建app.py,主程序

  1. from flask import request
  2. from flask_cors import *
  3.  
  4. from json_flask import JsonFlask
  5. from json_response import JsonResponse
  6. from config import *
  7.  
  8. import json
  9.  
  10. # 创建视图应用
  11. app = JsonFlask(__name__)
  12.  
  13. # 解决跨域
  14. CORS(app, supports_credentials=True)
  15.  
  16. db = SQLManager()
  17.  
  18. # 编写视图函数,绑定路由
  19. @app.route("/all", methods=["GET"]) # 查询(全部)
  20. def all():
  21. result = db.get_list(sql='select * from user')
  22. return JsonResponse.success(msg='查询成功', data=result)
  23.  
  24. @app.route("/add", methods=["POST"]) # 添加(单个)
  25. def add():
  26. data = json.loads(request.data) # 将json字符串转为dict
  27. isOk = db.modify(sql='insert into user(name,age,sex) values(%s,%s,%s)',
  28. args=[data['name'], data['age'], data['sex']])
  29. return JsonResponse.success(msg='添加成功') if isOk else JsonResponse.fail(msg='添加失败')
  30.  
  31. @app.route("/update", methods=["PUT"]) # 修改(单个)
  32. def update():
  33. data = json.loads(request.data) # 将json字符串转为dict
  34. if 'id' not in data:
  35. return JsonResponse.fail(msg='需要传入id')
  36. isOk = db.modify(sql='update user set name=%s,age=%s,sex=%s where id=%s',
  37. args=[data['name'], data['age'], data['sex'], data['id']])
  38. return JsonResponse.success(msg='修改成功') if isOk else JsonResponse.fail(msg='修改失败')
  39.  
  40. @app.route("/delete", methods=["DELETE"]) # 删除(单个)
  41. def delete():
  42. if 'id' not in request.args:
  43. return JsonResponse.fail(msg='需要传入id')
  44. isOk = db.modify(sql='delete from user where id=%s', args=[request.args['id']])
  45. return JsonResponse.success(msg='删除成功') if isOk else JsonResponse.fail(msg='删除失败')
  46.  
  47. # 运行flask:默认是5000端口,此处设置端口为666
  48. if __name__ == '__main__':
  49. app.run(host="0.0.0.0", port=666, debug=True)

启动项目。

数据库

采用MySQL,由于是小demo,此处设计较简单,数据库名为test,表名为user,表结构和数据SQL语句如下:

  1. SET NAMES utf8mb4;
  2. SET FOREIGN_KEY_CHECKS = 0;
  3.  
  4. -- ----------------------------
  5. -- Table structure for user
  6. -- ----------------------------
  7. DROP TABLE IF EXISTS `user`;
  8. CREATE TABLE `user` (
  9. `id` int(11) NOT NULL AUTO_INCREMENT,
  10. `name` varchar(255) CHARACTER SET gbk COLLATE gbk_chinese_ci NOT NULL,
  11. `age` int(11) NOT NULL,
  12. `sex` varchar(255) CHARACTER SET gbk COLLATE gbk_chinese_ci NOT NULL,
  13. PRIMARY KEY (`id`) USING BTREE
  14. ) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = gbk COLLATE = gbk_chinese_ci ROW_FORMAT = Compact;
  15.  
  16. -- ----------------------------
  17. -- Records of user
  18. -- ----------------------------
  19. INSERT INTO `user` VALUES (1, 'tom', 20, '男');
  20. INSERT INTO `user` VALUES (2, 'mary', 20, '女');
  21. INSERT INTO `user` VALUES (3, 'jack', 21, '男');
  22. INSERT INTO `user` VALUES (5, 'test', 20, '未知');
  23. INSERT INTO `user` VALUES (8, 'tom', 20, '男');
  24. INSERT INTO `user` VALUES (9, 'add', 20, '未知');
  25. INSERT INTO `user` VALUES (10, 'Saly', 11, '女');
  26.  
  27. SET FOREIGN_KEY_CHECKS = 1;

总结

到此这篇关于如何利用Python+Vue实现简单的前后端分离的文章就介绍到这了,更多相关Python+Vue实现前后端分离内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号