本文上篇请 点击阅读

1. 需求说明

本文以学生信息查询功能为例,采用前后端分离架构,后端提供RESTFul 接口,前端代码用Vue.js + Bottstrap实现。

1.1 本例要求提供如下查询功能:

列表查询、单条查询
添加学生信息
更改学生信息
删除学生信息

1.2 按REST接口指导原则, RESTFul 风格API 设计如下

在开始之前,推荐阅读 REST接口基本原理

操作请求类型资源请求url请求数据
列表查询GEThttp://127.0.0.1:8000/student/
单条查询GEThttp://127.0.0.1:8000/student/1/
添加记录POSThttp://127.0.0.1:8000/student/2/{‘name’:‘Jack’, ‘no’:‘A001’,…}
更改记录PUThttp://127.0.0.1:8000/student/2/{‘name’:‘Jack’, ‘no’:‘B001’,…}
删除记录DELETEhttp://127.0.0.1:8000/student/2/

上述接口已通过django-rest-framework 实现.

2. 前端设计

技术栈:

  • Vue.js 动态数据更新
  • Bootstrap5 负责渲染
  • Axios 负责接口通讯

界面设计:

  • 以表格方式显示多条数据;
  • 每行记录提供修改、删除按钮
  • 页面提供添加按钮
  • 页面提供查询功能
  • 各功能在单页面完成。

实际页面测试:
显示所有记录
在这里插入图片描述
查询单条数据
在这里插入图片描述
添加数据
在这里插入图片描述
修改数据,单击”修改“按钮后,弹出修改栏,更新后单击 ”提交“按钮
在这里插入图片描述
删除,直接点击删除按钮即可
在这里插入图片描述

3. 完整代码

所有代码均放在1个文件中, vue_student.html

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Vue 测试实例 - Vue router(runoob.com)</title>
	<link href="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/css/bootstrap.min.css" rel="stylesheet">
	<script src="https://cdn.staticfile.org/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
	<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
	<script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script>
	<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
	<div class="container mt-2">
		<div class="row  my-2 mx-2 ">
		    <div class="col-md-10 p-3">
				<h2 class="text-center">学生信息查询</h2>
				<div id='app'>
					<div class="container mt-3">
						<div class="row">
							<div class="col-md-6"> 
							<input type='number' v-model="sid" placeholder='请输入学生id'>
							<button v-on:click="searchInfo" class="btn btn-primary" >查询</button>
						    </div>
							<div class="col-md-6 d-flex flex-row-reverse">
								<button class="btn btn-info" v-on:click="addReq">添加学生</button>
							</div>
						</div>
					</div>
					<div class="row my-2 border border-1 border-primary shadow-sm py-2 mx-2" v-if="isShowDataDiv">
							
							<div class="form-group row">
								<label for="stdid" class="col-md-1 col-form-label" >ID</label>
								<div class="col-md-2"><input type="text" class="form-control" v-model="studentInfo.id" id="stdid" readonly="true"></div>
							    <label for="stdname" class="col-md-1 col-form-label">姓名</label>
							    <div class="col-md-2"><input type="text" class="form-control" v-model="studentInfo.name" id="stdname"></div>

								<label for="stdno" class="col-md-1 col-form-label">学号</label>
								<div class="col-md-2"><input type="text" class="form-control" v-model="studentInfo.no" id='stdno'  ></div>
								<div class='col-md-3 mt-2'>
								  <span>性别: &nbsp;</span>
								  <input type="radio" id="male" value=0 v-model="studentInfo.gender">
								  <label for="runoob" ></label>
								  <input type="radio" id="female" value=1 v-model="studentInfo.gender">
								  <label for="google"></label>
								</div>
							</div>
							<div class="form-group row">
								<label for="stdage" class="col-md-1 col-form-label">年龄</label>
								<div class="col-md-2"><input type="number" class="form-control" v-model="studentInfo.age" id="stdage"></div>
								<label for="stdclass" class="col-md-1 col-form-label">班级</label>
								<div class="col-md-2"><input type="text" class="form-control" v-model="studentInfo.class_name" id="stdclass"></div>
								<label for="stdscore" class="col-md-1 col-form-label">成绩</label>
								<div class="col-md-2"><input type="number" class="form-control" v-model="studentInfo.score" id="stdscore"></div>
								<div class="col-md-3 d-flex flex-row-reverse" v-if="isShowUpgradeBtn"><button class="btn btn-outline-primary" v-on:click="upgradeConfirm">更新提交</button></div>
								<div class="col-md-3 d-flex flex-row-reverse" v-if="isShowAddBtn"><button class="btn btn-outline-primary" v-on:click="addConfirm">添加提交</button></div>
							</div>
						
					</div>
					
					<table class="table table-striped">
						<thead>
							<tr>
								<td>ID</td>
								<td>姓名</td>
								<td>学号</td>
								<td>性别</td>
								<td>年龄</td>
								<td>班级</td>
								<td>成绩</td>
								<td>操作</td>
							</tr>
						</thead>
						<tbody>
							<tr v-for="(student,index) in studentArray">
								<td v-text="student.id"></td>
								<td v-text="student.name"></td>
								<td v-text="student.no"></td>
								<td v-text="student.gender"></td>
								<td v-text="student.age"></td>
								<td v-text="student.class_name"></td>
								<td v-text="student.score"></td>
								<td> <button class='btn btn-primary btn-sm' v-on:click="upgradeReq(student.id,index)">修改</button>  <button class='btn btn-danger btn-sm' v-on:click="deleteStudent(student.id,index)">删除</button></td>
							</tr>
						</tbody>
					</table>
				</div>
				
			</div>
		</div>		
	</div>
	
	<script>
	const url = "http://127.0.0.1:8000/student/v1/";
	var array_index; 
	var vm = new Vue({
		el: '#app',
		data: {
			studentInfo: {
				id: 1,
				name:'王小乙',
				no: 'B0001',
				gender: 0,
				age: 14,
				class_name: '初2',
				score: 80
			},
			studentArray: [],
			sid: 1,
			isShowDataDiv: false,
			isShowAddBtn: false,
			isShowUpgradeBtn: true
		},
		methods: {
			searchInfo: function(){
				that = this; 
				let url_req = url
				if(that.sid > 0){
					url_req = url+String(that.sid)+'/';
				} 
				
				axios.get(url_req)
					.then( function(response){
						console.log(response.data); 
						that.studentArray=[]
						if (response.data instanceof Array){							
							for (var n in response.data){
								that.studentArray.push(response.data[n]);
							}
						}
						else if (response.data instanceof Object ){
							that.studentArray.push(response.data);
						}						
					})
					.catch(function (error) { // 请求失败处理
						console.log(error);
					})
			},
			addData: function(){
				this.studentArray.push(this.studentInfo);
				
			},
			deleteStudent: function(pk,index){
				that = this;
				url_req = url+pk+'/';
				axios.delete(url_req)
					.then(function(response){ 
						console.log(response.status);
						that.studentArray.splice(index,1)
						})
					.catch(function(err){ console.log(err)})
			},
			addStudent: function(){
				window.open("vue_student_add.html");
			},
			addReq: function(){
				that=this;
				that.studentInfo = {
				id: 0,
				name:'',
				no: '',
				gender: 0,
				age: 0,
				class_name: '2',
				score: 0
				}
				that.isShowDataDiv=true;
				that.isShowUpgradeBtn=false;
				that.isShowAddBtn=true;
			},
			addConfirm: function(){
				that=this; 
				if (that.studentInfo.name !='' && that.studentInfo.no!='' ) {
					axios.post(url,that.studentInfo)
						.then(function(response){
							console.log(response);
							alert("添加成功")
							that.isShowDataDiv=false;
							that.isShowUpgradeBtn=true;
							that.isShowAddBtn=false;
							that.studentArray.push(that.studentInfo)							
						})
						.catch(function(err){
							console.log(err);
						})
				}
				else {
					alert("姓名,学号不能为空")
				}
				
			},
			upgradeReq: function(pk,index){
				that = this;
				that.studentInfo = that.studentArray[index];
				array_index = index; 
				that.isShowDataDiv=true;
				that.isShowUpgradeBtn=true;
				that.isShowAddBtn=false;
				// alert("update data " + pk)
			},
			upgradeConfirm: function(){
				that = this; 
				url_req = url+that.studentInfo.id+'/';
				axios.put(url_req,that.studentInfo)
					.then(response=>{
						console.log(response.status);
						that.studentArray[array_index]=that.studentInfo; 
						alert("更新成功")
						that.isShowDataDiv=false;
						
					})
					.catch(function(err){ console.log(err)})				
			}
		}
	});
	vm.addData()
	</script>
</body>
</html>

在测试环境下运行,通常会遇到CORS跨域问题,造成Axios发送的请求被阻止,解决办法请参考本人另一篇博文 Django 解决CORS跨域问题的方法.

总结

DRF+Vue.js 或 DRF+React 前后端分离架构的优点与缺点

采用 DRF+Vue.js 或 DRF+React 前后端分离架构的好处是,能够开发出用户体验更佳的前端页面,不过前提是,项目要有前端工程师加入,或者你自己学习掌握Javascript + Vue 技术,当然掌握了这两门工具,也会提升你的能力。另外,前后端分离项目,总体上会增加一些项目的代码量以及测试工作量。

如何确定项目是否适合采用DRF+Vue前后端分离架构呢?
如果用户对界面有较高要求,或者需要使用绘图、数据可视化等前端组件库(如 JointJS, echarts等),建议采用前后端分离架构。 如果项目的主要功能是以CRUD操作为主,或者数据分析为主,则使用django与模板方式,开发效率更高,
Logo

前往低代码交流专区

更多推荐