IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Flask+VUE 实现页面增删改查显示开发+测试(图文教程附源码) -> 正文阅读

[Python知识库]Flask+VUE 实现页面增删改查显示开发+测试(图文教程附源码)

作者:language-javascript

目录

一、新建项目并初始化

?二、安装依赖?axios、elementUI

三、Vue代码

四、进行接口联调

五、后端接口优化

六、web页面功能测试

七、总结

八、展望

九、附录(截止发文时的代码)


先来看看效果,再步入正题

主页

?增加

查询

详情

修改

删除

?先打一下地基

环境搭建博文:

VUE 3.0项目环境搭建+VS code安装(图文教程)_软件测试李同学的博客-CSDN博客

Flask+mysql接口增删改查博文:Flask+mysql实现增删改查接口开发+测试(图文教程附源码)_软件测试李同学的博客-CSDN博客

注意:本篇文章接着上面的图书项目book增删改查实现

一、新建项目并初始化

vue 创建新项目 :vue create book

初始化 :vue init webpack book

中间要是提示要安装脚手架:npm i -g @vue/cli-init

,按照提示执行命令即可

?安装:npm i -g @vue/cli-init

?

?

新建项目成功后,目录结构如下:

?二、安装依赖?axios、elementUI

axios说白了就是调接口用的

安装axios npm?
npm install axios --save
安装element-ui?
npm install element-ui --save (yarn add element-ui)

elementUI说白了就是一个组件库,很流行,实战的时候肯定是CV多,有轮子就不用重复写轮子

elementUI的引入

在src下面的main.js下新增如下内容
import Element from 'element-ui'
import "element-ui/lib/theme-chalk/index.css"
Vue.use(Element)

axios的引入
在src下面的main.js下新增如下内容
import axios from 'axios'
Vue.prototype.$axios=axios
组件中,我们就可以通过this.$axios.get()来发起我们的请求了哈

通过命令 npm run dev? 启动

三、Vue代码

以下代码也是轮子,轮子有了,先看看效果

向src->components->HelloWorld.vue文件中加入以下代码,然后保存

<!--
Element-ui框架实现对数据库的增删改查
这里利用Vue进行简单的增删改查操作,可以与后台进行结合,进行增删改查的过程,只需要将接口改一下名字。
其中element-ui组件库经常与vue进行结合使用
 -->
<template>
	<div class="back">
    <h1>{{ msg }}</h1>
		<el-button :span="8" type="primary" @click="adduser" class="add-btn" plain>
			添加信息
		</el-button>
		<el-input :span="8" placeholder="请输入内容" v-model="bookname" class="add-btn"
		clearable>
		</el-input>
		<el-button :span="8" slot="append" icon="el-icon-search" @click="check"
		class="button">
		</el-button>
		<el-table :data="bookInfo" style="width: 100%">
			<el-table-column prop="id" label="编号" width="180">
			</el-table-column>
			<el-table-column prop="name" label="书名" width="180">
			</el-table-column>
			<el-table-column prop="writer" label="作者" width="180">
			</el-table-column>
			<el-table-column prop="publish" label="出版社" width="180">
			</el-table-column>
			<el-table-column align="right">
				<!-- <template> -->
				<el-input placeholder="请输?书名搜索" v-model="bookname" clearable>
				</el-input>
				<el-button slot="append" icon="el-icon-search" @click="check" class="button">
				</el-button>
				<!-- </template> -->
				<template slot-scope="scope">
					<el-button size="mini" @click="edit(scope.row,scope.row.id)">
						编辑
					</el-button>
					<el-button size="mini" type="danger" @click.native.prevent="deleteRow(scope.row.id)">
						删除
					</el-button>
				</template>
			</el-table-column>
		</el-table>
		<!--增加框-->
		<el-dialog title="增加书籍信息" :visible.sync="dialogVisible1" width="30%" :before-close="handleClose1">
			<div>
				<el-form ref="form" :model="editObj1" label-width="80px">
					<el-form-item label="书名">
						<el-input v-model="editObj1.name">
						</el-input>
					</el-form-item>
					<el-form-item label="作者">
						<el-input v-model="editObj1.writer">
						</el-input>
					</el-form-item>
					<el-form-item label="出版社">
						<el-input v-model="editObj1.publish">
						</el-input>
					</el-form-item>
				</el-form>
			</div>
			<span slot="footer" class="dialog-footer">
				<el-button @click="dialogVisible1 = false">
					取消
				</el-button>
				<el-button type="primary" @click="confirm1">
					确定
				</el-button>
			</span>
		</el-dialog>
		<!--编辑框 -->
		<el-dialog title="编辑书籍信息" :visible.sync="dialogVisible" width="30%" :before-close="handleClose">
			<div>
				<el-form ref="form" :model="editObj" label-width="80px">
					<el-input type="hidden" v-model="editObj.id">
					</el-input>
					<el-form-item label="书名">
						<el-input v-model="editObj.name">
						</el-input>
					</el-form-item>
					<el-form-item label="作者">
						<el-input v-model="editObj.writer">
						</el-input>
					</el-form-item>
					<el-form-item label="出版社">
						<el-input v-model="editObj.publish">
						</el-input>
					</el-form-item>
				</el-form>
			</div>
			<span slot="footer" class="dialog-footer">
				<el-button @click="dialogVisible = false">
					取消
				</el-button>
				<el-button type="primary" @click="confirm">
					确定
				</el-button>
			</span>
		</el-dialog>
	</div>
</template>
<script>
	export default {
		data() {
			return {
        msg: "欢迎访问图书管理系统",
				dialogVisible: false,
				dialogVisible1: false,
				bookname: '',
				bookInfo: [{
					id: '',
					name: '',
					writer: '',
					publish: ''
				}],
				editObj: {
					id: '',
					name: '',
					writer: '',
					publish: ''
				},
				editObj1: {
					name: '',
					writer: '',
					publish: ''
				},
				userIndex: 0,
			}
		},
		mounted() {
			this.getnetwork();
		},
		methods: {
			getnetwork() {
				// console.log(this.bookinfo.id);
				var that = this 
        this.$axios.post("http://localhost:8081/springboot/getuser")
        .then(function(res) {
					console.log(res.data) 
          that.bookInfo = res.data
					// console.log(this.bookInfo)
				}).
				catch(function(err) {
					console.log(err)
				})
			},
			
			//确定查询按钮
			check() {
				// console.log(this.bookname)
				var that = this
				//网络请求获取数据axios
				 this.$axios.post("http://localhost:8081/springboot/checkbyname", {
					name: this.bookname,
				}).then(function(res) { //请求成功,方法回调
					//回调方法不能用this
					 console.log(res.data) 
           console.log(res.data.data) 
           that.bookInfo = res.data.data
					// console.log(this.data.id)
				}).
				catch(function(err) { //请求失败
					console.log(err)
				})
			},
			adduser() {
				this.dialogVisible1 = true;
			},
			edit(item, id) {
				this.userIndex = id;
				console.log(id)
				// console.log(item.id)
				// console.log(item.id)
				this.editObj = {
					id: item.id,
					name: item.name,
					writer: item.writer,
					publish: item.publish,
				};
				this.dialogVisible = true;
			},
			deleteRow(bookid) {
				console.log(bookid) 
        if (confirm('确定要删除吗') == true) {
					var that = this
					//网络请求获取数据axios
					 this.$axios.post("http://localhost:8081/springboot/deletebyid", {
						id: bookid
					})
          .then(res =>{ //请求成功,方法回调	
						//回调方法不能this
						this.getnetwork()
						// getnetwork();
						console.log(res.data) 
            that.newsList = res.data
						// console.log(this.newsList);
					}).catch(function(err) { //请求失败
						console.log("失败了" + err)
					})
				}
				// window.location.href = 'http://127.0.0.1:8848/HelloVue/book.html'
			},
			// ×按钮
			handleClose() {
				this.dialogVisible = false;
			},
			handleClose1() {
				this.dialogVisible1 = false;
			},
			confirm() { //确认修改
				console.log(this.editObj.id) 
        console.log(this.editObj.name) 
        console.log(this.editObj.publish) 
        console.log(this.editObj.writer) 
        var that = this
				//网络请求获取数据axios
				 this.$axios.post("http://localhost:8081/springboot/updateuser", {
					id: this.editObj.id,
					name: this.editObj.name,
					publish: this.editObj.publish,
					writer: this.editObj.writer
				}).then(function(res) { //请求成功,方法回调
					//回调?方不能this
					 that.getnetwork() 
           console.log(res.data) 
           that.newsList = res.data
				}).catch(function(err) { //请求失败
					console.log(err)
				}) 
        this.dialogVisible = false;
				// Vue.set(this.tableData, this.userIndex, this.editObj);
			},
			// 确定增加按钮
			confirm1() {
				var that = this
				//网络请求获取数据axios
				 this.$axios.post("http://localhost:8081/springboot/adduser", {
					name: this.editObj1.name,
					publish: this.editObj1.publish,
					writer: this.editObj1.writer
				})
        .then(function(res) { //请求成功,方法回调
				//回调方法不能用this
				that.getnetwork() 
        console.log(res.data) 
        that.newsList = res.data
					}).
					catch(function(err) { //请求失败
						console.log(err)
					}) 
          this.dialogVisible1 = false;
					// Vue.set(this.tableData, this.userIndex, this.editObj);
				}
			},
		}
</script>
<style>
	.add-btn{ width:450px } 
  .input{ width: 220px; height: 70px; } 

  .button{}

	#app{ width: 1024px; margin: 0 auto; } 
  #back{ height: 200px; }
</style>

运行看看效果

?页面画好了,下一步和后端接口联调

四、进行接口联调

继续联调,发现vue文件还有很多需要改的地方

理智分析一波

1、先是先将对应的模板<template>写好,包括输入框(查找操作),增加按钮(增加操作),删除按钮(删除操作),修改按钮(修改操作),表格(显示数据)

模板代码如下:

<template>
	<div class="back">
    <h1>{{ msg }}</h1>
		<el-button :span="8" type="primary" @click="addbook" class="add-btn" plain>
			添加图书
		</el-button>
		<el-input :span="8" placeholder="请输入编号搜索" v-model="id" class="add-btn"
		clearable>
		</el-input>
		<el-button :span="8" slot="append" icon="el-icon-search" @click="check"
		class="button">
		</el-button>
		<el-table :data="bookInfo" style="width: 100%">
			<el-table-column prop="id" label="编号" width="180">
			</el-table-column>
			<el-table-column prop="title" label="书名" width="180">
						<template slot='header'>
							<span class ="star">*</span>
							<span >书名</span>
						</template>
			</el-table-column>
			<el-table-column prop="author" label="作者" width="180">
						<template slot='header'>
							<span class ="star">*</span>
							<span >作者</span>
						</template>
			</el-table-column>
			<!-- 表头提示在这里用 -->
			<el-table-column prop="read_status" label="阅读状态" width="180" :render-header="renderHeader">
				<!-- 这里红星星没生效还需要找原因 -->
						<template slot='header'>
							<span class ="star">*</span>
							<span >阅读状态</span>
						</template>
			</el-table-column>
			<el-table-column align="right">
				<template slot-scope="scope">
					<!-- plain改变按钮显示方式,element 称为朴素按钮-->
					<el-button size="mini" type="info" @click="detail(scope.row,scope.row.id)" >
			            详情
		            </el-button>
					<el-button size="mini" type="success" @click="edit(scope.row,scope.row.id)">
						编辑
					</el-button>
					<el-button size="mini" type="danger" @click.native.prevent="deleteRow(scope.row.id)">
						删除
					</el-button>
				</template>
			</el-table-column>
		</el-table>
		<!-- 数据分页页面,还没做好-->
		<div class="block" >
			<!--换行用br标签-->
			<br><br/>
			<el-pagination
			@size-change="handleSizeChange"
			@current-change="handleCurrentChange"
			:current-page="currentPage4"
			:page-sizes="[20, 30, 50, 100]"
			:page-size="100"
			layout="total, sizes, prev, pager, next, jumper"
			:total="400">
			</el-pagination>
		</div>
		<!--增加对话框-->
		<el-dialog title="增加图书信息" :visible.sync="addbook_dialogVisible" width="30%" :before-close="handleClose1">
			<div>
				<el-form ref="form" :model="editObj1" label-width="80px">
					<el-form-item label="书名" required="true">
						<el-input v-model="editObj1.title" placeholder="请输入书名">
						</el-input>
					</el-form-item>
					<el-form-item label="作者" required="true">
						<el-input v-model="editObj1.author" placeholder="请输入作者">
						</el-input>
					</el-form-item>
					<!--鼠标在此标签区域显示提示-->
					<el-form-item label="阅读状态" required="true" title="阅读状态只能输入0或者1;0代表未读,1代表已读">
						<el-input v-model="editObj1.read_status" placeholder="请输入阅读状态">
						</el-input>
					</el-form-item>
				</el-form>
			</div>
			<span slot="footer" class="dialog-footer">
				<el-button @click="addbook_dialogVisible = false">取消</el-button>
				<el-button type="primary" @click="confirm_add">确定</el-button>
			</span>
		</el-dialog>
		<!--编辑对话框 -->
		<el-dialog title="编辑图书信息" :visible.sync="edit_dialogVisible" width="30%" :before-close="handleClose">
			<div>
				<el-form ref="form" :model="editObj" label-width="80px">
					<el-input type="hidden" v-model="editObj.id"></el-input>
					<!--required显示红星表示必填项,placeholder为输入框注释 -->
					<el-form-item label="书名" required="true" >
						<el-input v-model="editObj.title" placeholder="请输入书名"></el-input>
					</el-form-item>
					<el-form-item label="作者" required="true" >
						<el-input v-model="editObj.author" placeholder="请输入作者"></el-input>
					</el-form-item>
					<el-form-item label="阅读状态" required="true" title="阅读状态只能输入0或者1;0代表未读,1代表已读">
						<el-input v-model="editObj.read_status" placeholder="请输入阅读状态"></el-input>
					</el-form-item>
				</el-form>
			</div>
			<span slot="footer" class="dialog-footer">
				<el-button @click="edit_dialogVisible = false">取消</el-button>
				<el-button type="primary" @click="confirm">确定</el-button>
			</span>
		</el-dialog>
		<!--详情对话框,新建一个对话框把编辑的代码复制过来,然后逻辑复制编辑额逻辑,再把确定和取消按钮去掉即可 -->
				<el-dialog title="图书详情信息" :visible.sync="detail_dialogVisible" width="30%" :before-close="detail_handleClose">
			<div>
				<el-form ref="form" :model="editObj" label-width="80px">
					<el-input type="hidden" v-model="editObj.id"></el-input>
					<el-form-item label="书名" required="true">
						<el-input v-model="editObj.title" :disabled="true"></el-input>
					</el-form-item>
					<el-form-item label="作者" required="true">
						<el-input v-model="editObj.author" :disabled="true"></el-input>
					</el-form-item>
					<el-form-item label="阅读状态" required="true" title="阅读状态只能输入0或者1;0代表未读,1代表已读">
						<el-input v-model="editObj.read_status" :disabled="true"></el-input>
					</el-form-item>
				</el-form>
			</div>
			<!--详情对话框的确定和取消按钮去掉 
			<span slot="footer" class="dialog-footer">
				<el-button @click="edit_dialogVisible = false">取消</el-button>
				<el-button type="primary" @click="confirm">确定</el-button>
			</span>
			-->
		</el-dialog>
	</div>
</template>


2、制作好模板之后,就得编写下各个方法,包括显示数据方法(getnetwork)增加方法(confirm_add),删除方法(deleteRow),查询方法(check),修改方法(confirm)

显示方法代码如下:

			getnetwork() {
				// console.log(this.bookinfo.id);
				var that = this 
                this.$axios.post("http://127.0.0.1:5001/query",{
					id: "",  //这里不传id查所有
				})
                .then(function(res) {
					console.log(res.data) 
                    that.bookInfo = res.data.data
				    that.bookInfo = that.bookInfo.map(item=>{
					item.read_status = String(item.read_status)
					return item
				}
				)
					// console.log(this.bookInfo)
				}).
				catch(function(err) {
					console.log(err)
				})
			}

增加方法(confirm_add)如下:

			//5、 增加方法
			confirm_add() {// 确定增加按钮
			if (this.editObj1.title === '') {
          		this.$message({
            	message: '书名不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj1.author === '') {
          		this.$message({
            	message: '作者不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj1.read_status === '') {
          		this.$message({
            	message: '阅读状态不能为空!',
           		type: 'warning'
          		});
          		return
        	}
				var that = this
				//网络请求获取数据axios
				this.$axios.post("http://127.0.0.1:5001/add", {
					title: this.editObj1.title,
					author: this.editObj1.author,
					read_status: this.editObj1.read_status
				}).then(function(res) { //请求成功,方法回调
              	//	this.$message.success('图书添加成功!');
				
				//回调方法不能用this
				that.getnetwork() 
				// if (this.editObj1.read_status == success)
                console.log(res.data)
                //that.newsList = res.data
					}).catch(function(err) { //请求失败
						console.log(err)
					}) 
            	this.addbook_dialogVisible = false;
				// Vue.set(this.tableData, this.userIndex, this.editObj);

			},
			// 给表头增加提示
    		renderHeader(h,{column}){
        	const serviceContent= [
            h('div',{
                slot:"content",
            },
            "提示:true代表已读,false代表未读"
            )
        		]
        		return h("div",[
            		h("span",column.label),
           			h("el-tooltip",{
                props:{
                    placement:"top"
                }
            },
            [
                serviceContent,
                h("i",{
                    class:"el-icon-warning-outline",
                    style:"color:blue;margin-left:5px;"
                })
            ])
        ]);
    },
			},
		}

删除方法(deleteRow)如下:

			//3、删除方法
			deleteRow(id) {
				console.log(id) 
        		if (confirm('确定要删除吗') == true) {
					var that = this
					//网络请求获取数据axios
					 this.$axios.post("http://127.0.0.1:5001/delete", {
						id:id
					})
          			.then(res =>{ //请求成功,方法回调	
						//回调方法不能this
						this.getnetwork()
						// getnetwork();
						console.log(res.data) 
					}).catch(function(err) { //请求失败
						console.log("失败了" + err)
					})
				}
			},
			// 对话框右上角的×按钮
			handleClose() {//编辑
				this.edit_dialogVisible = false;
			},
			handleClose1() {//增加
				this.addbook_dialogVisible = false;
			},
			detail_handleClose() {//详情
				this.detail_dialogVisible = false;
			}

查询方法(check)如下:

			//2、查询方法
			check() {//确定查询按钮
				// console.log(this.bookname)
				var that = this
				//网络请求获取数据axios
				 this.$axios.post("http://127.0.0.1:5001/query", {
					id: this.id,
				}).then(function(res) { //请求成功,方法回调
					//回调方法不能用this
					console.log(res.data) 
           	   		console.log(res.data.data) 
           	   		that.bookInfo = res.data.data
		   	   		that.bookInfo = that.bookInfo.map(item=>{//布尔类型转字符串
			   		item.read_status = String(item.read_status)
			       		return item
		        })
					// console.log(this.data.id)
				}).
				catch(function(err) { //请求失败
					console.log(err)
				})
			},

修改方法(confirm)?如下:

			//4、修改方法
			confirm() { //确认修改
			if (this.editObj.title === '') {
          		this.$message({
            	message: '书名不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj.author === '') {
          		this.$message({
            	message: '作者不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj.read_status === '') {
          		this.$message({
            	message: '阅读状态不能为空!',
           		type: 'warning'
          		});
          		return
        	}
        		var that = this
				//网络请求获取数据axios
				this.$axios.post("http://127.0.0.1:5001/update", {
					id: this.editObj.id,
					title: this.editObj.title,
					author: this.editObj.author,
					read_status: this.editObj.read_status
				}).then(function(res) { //请求成功,方法回调
					//回调方法不能this	
									
					that.getnetwork()
					
           			console.log(res.data) 
				}).catch(function(err) { //请求失败
					console.log(err)
				}) 
       			 this.edit_dialogVisible = false;
				// Vue.set(this.tableData, this.userIndex, this.editObj);
			},

五、后端接口优化

1、传单个id的时候返回的单个数据没在数组里,这里要处理一下

2、删除的方法由DELETE改为POST

3、。。。。还有很多别的,具体看代码

六、web页面功能测试

准备测试,看看增删改查效果

增加

删除

?

修改

查询

查询所有

通过编号查询?

其他的测试场景和细节体验这里就不测试了

代码的注释已经写得很清楚了?

七、总结

上一篇博文的代码有一些bug,不知道大家找出来没。这一次做的增删改查前端加入了很多小细节,基本是就是工作中需要测试的细节,如果是自己实现的话,这个会给大家带来很深的印象。

还有对阅读状态这个布尔型字段的处理,有点费功夫的,坑也多

八、期望

很多校验还没做好,还有很多bug,前期设计不太合理,后续需要优化。

1、更改为书名查询,模糊查询

2、修复增加和修改后页面自动按照id查询的bug。。。等bug

3、增加输入框长度校验、提示校验,目前做的还不够

4、增加操作成功和失败后的提示

5、删除确认框的处理

6、做好分页功能

7、做好封装,接口、方法等

8、。。。。。。

完成以上工作,一个健壮的增删改查就有了,已经满足工作的要求了

九、附录(截止发文时的代码)

1、后端app.py全部代码

# -*- coding: utf-8 -*-
# @Author  : Liqiju
# @Time    : 2022/5/1 2:45
# @File    : app.py
# @Software: PyCharm
import pymysql
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask import make_response,request
from flask_cors import CORS
pymysql.install_as_MySQLdb()

app = Flask(__name__)
# ------------------database----------------------------
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:root@localhost:3306/books'
# 指定数据库文件
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

# 允许修改跟踪数据库
db = SQLAlchemy(app)


class Books(db.Model):
    id = db.Column(db.Integer, primary_key=True, comment='自动递增id,唯一键')
    title = db.Column(db.String(80), nullable=False, comment='书名')
    author = db.Column(db.String(120), nullable=False, comment='作者')
    read_status = db.Column(db.Boolean, comment='阅读状态,0未读,1已读') # bool的True和False是数值1和0


# 增加数据
def insert_data(title, author, read_status):
    book = Books(title=title, author=author, read_status=read_status)
    db.session.add_all([book])
    db.session.commit()


# 查询所有
def select_data_all():
    book_list = []
    books = Books.query.all()
    # 类似于 select * from Books

    for s in books:
        dic = {}
        dic['id'] = s.id
        dic['title'] = s.title
        dic['author'] = s.author
        dic['read_status'] = s.read_status
        book_list.append(dic)
    return book_list


# 通过id查询
def select_data_by_id(id):
    book_list = []
    book = Books.query.get(id)
    if not book:
        return False
    dic = {}
    dic['id'] = book.id
    dic['title'] = book.title
    dic['author'] = book.author
    dic['read_status'] = book.read_status
    book_list.append(dic)
    return book_list


# 通过id删除数据
def delete_data(id):
    # 类似于 select * from Books where id = id
    delete_id = Books.query.get(id)
    if not delete_id:
        return False
    db.session.delete(delete_id)
    db.session.commit()
    # 提交操作到数据库


# 修改数据
def update_data(id, title='', author='', read_status=''):
    book = Books.query.get(id)
    if not title == '':
        book.title = title
    if not author == '':
        book.author = author
    if not read_status == '':
        book.read_status = read_status
    db.session.commit()


# 解决浏览器浏览器访问输出乱码问题
app.config['JSON_AS_ASCII'] = False


@app.after_request
def after(resp):
    resp = make_response(resp)
    resp.headers['Access-Control-Allow-Origin'] = '*'  # 允许跨域地址
    resp.headers['Access-Control-Allow-Methods'] = '*'  # 请求 ‘*’ 就是全部
    resp.headers['Access-Control-Allow-Headers'] = 'x-requested-with,content-type'  # 头部
    resp.headers['Access-Control-Allow-Credentials'] = 'True'
    return resp


CORS(app, resources=r'/*', supports_credentials=True)


# 前端通过传参title、author、read_status增加书籍
@app.route('/add', methods=['POST'])
def add():
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json()
        print('调用add方传过来的参数是', post_data)
        book_list = select_data_all()
        for i in range(len(book_list)):
            title_list = book_list[i]['title']
        if post_data.get('title') in title_list:
            response_object['message'] = '书名(title)重复!'
            response_object["status"]= 'fail'
            return response_object
        if post_data.get('title') is None:
            response_object['message'] = 'title是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        if post_data.get('author') is None:
            response_object['message'] = 'author是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        if post_data.get('read_status') is None:
            response_object['message'] = 'read_status是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        title = str(post_data.get('title')).strip(),
        author = str(post_data.get('author')).strip(),
        read_status = int(str(post_data.get('read_status')))# 前端传过来字符串处理为int

        if title[0] is None or title[0] is '':
            response_object['message'] = 'title不能为空!'
            response_object["status"] = 'fail'
            return response_object
        if author[0] is None or author[0] is '':
            response_object['message'] = '作者不能为空!'
            response_object["status"] = 'fail'
            return response_object
        if read_status != 0 and read_status != 1:
            response_object['message'] = '阅读状态只能为0和1!'
            response_object["status"] = 'fail'
            return response_object
        insert_data(title=title[0], author=author[0], read_status=read_status)
        response_object['message'] = '图书添加成功!'
    return response_object


# 前端通过传id删除书籍
@app.route('/delete', methods=['POST'])  # 改为post方法
def delete():
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json()
        print('调用delete方传过来的参数是:', post_data)
        if post_data.get('id') is None:
            response_object['message'] = 'id是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        id = post_data.get('id')
        result = delete_data(id)  # 删除方法调用
        if result is False:
            response_object['message'] = '需要删除的图书不存在!'
            response_object["status"] = 'fail'
            return response_object
        else:
            response_object['message'] = '图书被删除!'
            return response_object


# 前端通过传参title、author、read_status修改书籍
@app.route('/update', methods=['POST'])
def update():
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json()
        print('调用update方传过来的参数是', post_data)
        if post_data.get('id') is None:
            response_object['message'] = 'id是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        if post_data.get('title') is None:
            response_object['message'] = 'title是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        if post_data.get('author') is None:
            response_object['message'] = 'author是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        if post_data.get('read_status') is None:
            response_object['message'] = 'read_status是必传参数!'
            response_object["status"]= 'fail'
            return response_object
        # 查询所有数据
        book_list = select_data_all()
        # 拼接所有的id到列表
        print(book_list)
        #  这里的逻辑写错了,有bug,改一下
        book_id = []
        for i in range(len(book_list)):
            book_id.append(book_list[i]['id'])
        print('book_id是', book_id)
        # 判断书籍id在不在列表内
        if post_data.get('id') not in book_id and int(post_data.get('id')) not in book_id: #  这里也有bug,改一下
            response_object['message'] = '需要修改的图书id不存在!'
            response_object["status"]= 'fail'
            return response_object
        title = str(post_data.get('title')).strip(),
        author = str(post_data.get('author')).strip(),
        #print("处理前",post_data.get('read_status'))
        read_status = int(post_data.get('read_status'))  # 前端传过来字符串处理为int
        #print("处理后", read_status)
        if title[0] is None or title[0] is '':
            response_object['message'] = 'title不能为空!'
            response_object["status"] = 'fail'
            return response_object
        if author[0] is None or author[0] is '':
            response_object['message'] = '作者不能为空!'
            response_object["status"] = 'fail'
            return response_object
        if read_status != 0 and read_status != 1:
            response_object['message'] = '阅读状态只能为0和1!'
            response_object["status"] = 'fail'
            return response_object

        books_id = post_data.get('id')
        title = post_data.get('title')
        author = post_data.get('author')
        read_status = read_status
        # 这里原来的post_data.get('read_status')改为read_status,上面已经处理了
        update_data(id=books_id, title=title, author=author, read_status=read_status)
        response_object['message'] = '图书已更新!'
        return response_object


# 前端通过不传参默认查询所有书籍,传id查询对应书籍
@app.route('/query', methods=['POST'])
def query():
    response_object = {'status': 'success'}
    if request.method == 'POST':
        post_data = request.get_json()
        print('调用query方传过来的参数是', post_data)
        # if post_data.get('id') is None:
        id = str(post_data.get('id')).strip()
        if id is None or id is '':
            books = select_data_all()
            response_object['message'] = '查询所有图书成功!'
            response_object['data'] = books
            return response_object
        # id = str(post_data.get('id')).strip()
        # if id is None or id is '':
        #     response_object['message'] = 'id不能为空!'
        #     response_object["status"] = 'fail'
        #     return response_object
        book = select_data_by_id(id)
        if book is False:
            response_object['message'] = '需要查询的图书不存在!'
            response_object["status"] = 'fail'
            return response_object
        else:
            response_object['message'] = '图书查询成功!'
            response_object['data'] = book
            return response_object


if __name__ == '__main__':
    # 默认是5000,这里设置5001避免本地冲突。打开debug方便调试
    # db.create_all()  # 创建表(表创建好后可注释掉)
    # insert_data("《水浒传》", "吴承恩", 1) # 利用这个可以添加数据或者直接数据库手动加入
                                            # 注意这个时候没开启校验title唯一性是因为不是前端过来的请求
    app.run(debug=True, port=5001)

2、前端HelloWorld.vue全部代码

<!--
Element-ui框架实现对数据库的增删改查
这里利用Vue进行简单的增删改查操作,可以与后台进行结合,进行增删改查的过程,只需要将接口改一下名字。
其中element-ui组件库经常与vue进行结合使用
vue被称为组件,那是因为一个vue文件由HTML、JS、CSS构成
 -->
 <!--一、 HTML部分,用的是element-ui 模板template -->
<template>
	<div class="back">
    <h1>{{ msg }}</h1>
		<el-button :span="8" type="primary" @click="addbook" class="add-btn" plain>
			添加图书
		</el-button>
		<el-input :span="8" placeholder="请输入编号搜索" v-model="id" class="add-btn"
		clearable>
		</el-input>
		<el-button :span="8" slot="append" icon="el-icon-search" @click="check"
		class="button">
		</el-button>
		<el-table :data="bookInfo" style="width: 100%">
			<el-table-column prop="id" label="编号" width="180">
			</el-table-column>
			<el-table-column prop="title" label="书名" width="180">
						<template slot='header'>
							<span class ="star">*</span>
							<span >书名</span>
						</template>
			</el-table-column>
			<el-table-column prop="author" label="作者" width="180">
						<template slot='header'>
							<span class ="star">*</span>
							<span >作者</span>
						</template>
			</el-table-column>
			<!-- 表头提示在这里用 -->
			<el-table-column prop="read_status" label="阅读状态" width="180" :render-header="renderHeader">
				<!-- 这里红星星没生效还需要找原因 -->
						<template slot='header'>
							<span class ="star">*</span>
							<span >阅读状态</span>
						</template>
			</el-table-column>
			<el-table-column align="right">
				<template slot-scope="scope">
					<!-- plain改变按钮显示方式,element 称为朴素按钮-->
					<el-button size="mini" type="info" @click="detail(scope.row,scope.row.id)" >
			            详情
		            </el-button>
					<el-button size="mini" type="success" @click="edit(scope.row,scope.row.id)">
						编辑
					</el-button>
					<el-button size="mini" type="danger" @click.native.prevent="deleteRow(scope.row.id)">
						删除
					</el-button>
				</template>
			</el-table-column>
		</el-table>
		<!-- 数据分页页面,还没做好-->
		<div class="block" >
			<!--换行用br标签-->
			<br><br/>
			<el-pagination
			@size-change="handleSizeChange"
			@current-change="handleCurrentChange"
			:current-page="currentPage4"
			:page-sizes="[20, 30, 50, 100]"
			:page-size="100"
			layout="total, sizes, prev, pager, next, jumper"
			:total="400">
			</el-pagination>
		</div>
		<!--增加对话框-->
		<el-dialog title="增加图书信息" :visible.sync="addbook_dialogVisible" width="30%" :before-close="handleClose1">
			<div>
				<el-form ref="form" :model="editObj1" label-width="80px">
					<el-form-item label="书名" required="true">
						<el-input v-model="editObj1.title" placeholder="请输入书名">
						</el-input>
					</el-form-item>
					<el-form-item label="作者" required="true">
						<el-input v-model="editObj1.author" placeholder="请输入作者">
						</el-input>
					</el-form-item>
					<!--鼠标在此标签区域显示提示-->
					<el-form-item label="阅读状态" required="true" title="阅读状态只能输入0或者1;0代表未读,1代表已读">
						<el-input v-model="editObj1.read_status" placeholder="请输入阅读状态">
						</el-input>
					</el-form-item>
				</el-form>
			</div>
			<span slot="footer" class="dialog-footer">
				<el-button @click="addbook_dialogVisible = false">取消</el-button>
				<el-button type="primary" @click="confirm_add">确定</el-button>
			</span>
		</el-dialog>
		<!--编辑对话框 -->
		<el-dialog title="编辑图书信息" :visible.sync="edit_dialogVisible" width="30%" :before-close="handleClose">
			<div>
				<el-form ref="form" :model="editObj" label-width="80px">
					<el-input type="hidden" v-model="editObj.id"></el-input>
					<!--required显示红星表示必填项,placeholder为输入框注释 -->
					<el-form-item label="书名" required="true" >
						<el-input v-model="editObj.title" placeholder="请输入书名"></el-input>
					</el-form-item>
					<el-form-item label="作者" required="true" >
						<el-input v-model="editObj.author" placeholder="请输入作者"></el-input>
					</el-form-item>
					<el-form-item label="阅读状态" required="true" title="阅读状态只能输入0或者1;0代表未读,1代表已读">
						<el-input v-model="editObj.read_status" placeholder="请输入阅读状态"></el-input>
					</el-form-item>
				</el-form>
			</div>
			<span slot="footer" class="dialog-footer">
				<el-button @click="edit_dialogVisible = false">取消</el-button>
				<el-button type="primary" @click="confirm">确定</el-button>
			</span>
		</el-dialog>
		<!--详情对话框,新建一个对话框把编辑的代码复制过来,然后逻辑复制编辑额逻辑,再把确定和取消按钮去掉即可 -->
				<el-dialog title="图书详情信息" :visible.sync="detail_dialogVisible" width="30%" :before-close="detail_handleClose">
			<div>
				<el-form ref="form" :model="editObj" label-width="80px">
					<el-input type="hidden" v-model="editObj.id"></el-input>
					<el-form-item label="书名" required="true">
						<el-input v-model="editObj.title" :disabled="true"></el-input>
					</el-form-item>
					<el-form-item label="作者" required="true">
						<el-input v-model="editObj.author" :disabled="true"></el-input>
					</el-form-item>
					<el-form-item label="阅读状态" required="true" title="阅读状态只能输入0或者1;0代表未读,1代表已读">
						<el-input v-model="editObj.read_status" :disabled="true"></el-input>
					</el-form-item>
				</el-form>
			</div>
			<!--详情对话框的确定和取消按钮去掉 
			<span slot="footer" class="dialog-footer">
				<el-button @click="edit_dialogVisible = false">取消</el-button>
				<el-button type="primary" @click="confirm">确定</el-button>
			</span>
			-->
		</el-dialog>
	</div>
</template>

<!--二、下面是JS部分-->
<script>
	export default {
		data() {
			return {
        msg: "欢迎访问图书管理系统",
				edit_dialogVisible: false,
				addbook_dialogVisible: false,
				detail_dialogVisible: false,
				id: '',
				title: '',
				author: '',
				read_status: '',
				bookInfo: [{
					id: '',
					title: '',
					author: '',
					read_status: ''
				}],
				editObj: {
					id: '',
					title: '',
					author: '',
					read_status: ''
				},
				editObj1: {
					title: '',
					author: '',
					read_status: ''
				},
				userIndex: 0,
			}
		},
		mounted() {
			this.check();
		},
		methods: {
			//1、显示方法
			getnetwork() {
				// console.log(this.bookinfo.id);
				var that = this 
                this.$axios.post("http://127.0.0.1:5001/query",{
					id: "",  //这里不传id查所有
				})
                .then(function(res) {
					console.log(res.data) 
                    that.bookInfo = res.data.data
				    that.bookInfo = that.bookInfo.map(item=>{
					item.read_status = String(item.read_status)
					return item
				}
				)
					// console.log(this.bookInfo)
				}).
				catch(function(err) {
					console.log(err)
				})
			},
			
			//2、查询方法
			check() {//确定查询按钮
				// console.log(this.bookname)
				var that = this
				//网络请求获取数据axios
				 this.$axios.post("http://127.0.0.1:5001/query", {
					id: this.id,
				}).then(function(res) { //请求成功,方法回调
					//回调方法不能用this
					console.log(res.data) 
           	   		console.log(res.data.data) 
           	   		that.bookInfo = res.data.data
		   	   		that.bookInfo = that.bookInfo.map(item=>{//布尔类型转字符串
			   		item.read_status = String(item.read_status)
			       		return item
		        })
					// console.log(this.data.id)
				}).
				catch(function(err) { //请求失败
					console.log(err)
				})
			},
			addbook() {
				this.addbook_dialogVisible = true;
			},
			edit(item, id) {
				this.id = id;
				console.log(id)
				this.editObj = {
					id: item.id,
					title: item.title,
					author: item.author,
					read_status: item.read_status,
				};
				this.edit_dialogVisible = true;
			},
			detail(item, id) {
				this.id = id;
				console.log(id)
				this.editObj = {
					id: item.id,
					title: item.title,
					author: item.author,
					read_status: item.read_status,
				};
				this.detail_dialogVisible = true;
			},
			//3、删除方法
			deleteRow(id) {
				console.log(id) 
        		if (confirm('确定要删除吗') == true) {
					var that = this
					//网络请求获取数据axios
					 this.$axios.post("http://127.0.0.1:5001/delete", {
						id:id
					})
          			.then(res =>{ //请求成功,方法回调	
						//回调方法不能this
						this.getnetwork()
						// getnetwork();
						console.log(res.data) 
					}).catch(function(err) { //请求失败
						console.log("失败了" + err)
					})
				}
			},
			// 对话框右上角的×按钮
			handleClose() {//编辑
				this.edit_dialogVisible = false;
			},
			handleClose1() {//增加
				this.addbook_dialogVisible = false;
			},
			detail_handleClose() {//详情
				this.detail_dialogVisible = false;
			},
			//4、修改方法
			confirm() { //确认修改
			if (this.editObj.title === '') {
          		this.$message({
            	message: '书名不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj.author === '') {
          		this.$message({
            	message: '作者不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj.read_status === '') {
          		this.$message({
            	message: '阅读状态不能为空!',
           		type: 'warning'
          		});
          		return
        	}
        		var that = this
				//网络请求获取数据axios
				this.$axios.post("http://127.0.0.1:5001/update", {
					id: this.editObj.id,
					title: this.editObj.title,
					author: this.editObj.author,
					read_status: this.editObj.read_status
				}).then(function(res) { //请求成功,方法回调
					//回调方法不能this	
									
					that.getnetwork()
					
           			console.log(res.data) 
				}).catch(function(err) { //请求失败
					console.log(err)
				}) 
       			 this.edit_dialogVisible = false;
				// Vue.set(this.tableData, this.userIndex, this.editObj);
			},
			//5、 增加方法
			confirm_add() {// 确定增加按钮
			if (this.editObj1.title === '') {
          		this.$message({
            	message: '书名不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj1.author === '') {
          		this.$message({
            	message: '作者不能为空!',
           		type: 'warning'
          		});
          		return
        	}
			if (this.editObj1.read_status === '') {
          		this.$message({
            	message: '阅读状态不能为空!',
           		type: 'warning'
          		});
          		return
        	}
				var that = this
				//网络请求获取数据axios
				this.$axios.post("http://127.0.0.1:5001/add", {
					title: this.editObj1.title,
					author: this.editObj1.author,
					read_status: this.editObj1.read_status
				}).then(function(res) { //请求成功,方法回调
              	//	this.$message.success('图书添加成功!');
				
				//回调方法不能用this
				that.getnetwork() 
				// if (this.editObj1.read_status == success)
                console.log(res.data)
                //that.newsList = res.data
					}).catch(function(err) { //请求失败
						console.log(err)
					}) 
            	this.addbook_dialogVisible = false;
				// Vue.set(this.tableData, this.userIndex, this.editObj);

			},
			// 给表头增加提示
    		renderHeader(h,{column}){
        	const serviceContent= [
            h('div',{
                slot:"content",
            },
            "提示:true代表已读,false代表未读"
            )
        		]
        		return h("div",[
            		h("span",column.label),
           			h("el-tooltip",{
                props:{
                    placement:"top"
                }
            },
            [
                serviceContent,
                h("i",{
                    class:"el-icon-warning-outline",
                    style:"color:blue;margin-left:5px;"
                })
            ])
        ]);
    },
			},
		}
</script>
<!-- 三、CSS部分 颜色、样式自己调试,这里就能体会有UI工程师的好处-->
<style>
/**标签为class属性就用.修饰,标签属性为id的话用#修饰。**/
	.add-btn{ width:450px }   
    .input{ width: 220px; height: 70px; } 
    .button{
		color: rgb(246, 241, 248);
    	background-color: rgb(187, 187, 221);
	}
	#app{ width: 1024px; margin: 0 auto; } 
    #back{ height: 200px; }
	.block{text-align:left}
	.star{
		color: #F56C6C;
		font-size: 14px;
		margin-right: 4px;
	}
</style>

有疑问来评论区或者私信一起学习交流

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-05-09 12:36:21  更:2022-05-09 12:36:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/27 20:11:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计