前言: 网上Django项目要么太老,要么不全。正好手里有个需求,借这个机会用django3.2加vue3(TS)一步步完整搭建一个图纸管理系统。一方面是记录,另一方面也回馈开源精神。希望和大家一起学习一起进步。本篇为前后端交互(最近更新7.26)
经过我们前期的努力,已经完成了后端前端的编写。那么接下来就是进行积木搭建的最后一步了!前后端交互!
三、前后端交互
1、前端跨域获取后端接口数据
这里简单说下这个流程大概是什么样子的:
a:前端如何发送获取数据的请求
axios-->Ajax
前端访问地址:http://localhost:8080/
b:后端接受请求,去数据库查询数据,返回json数据给前端
DRF --> 接口
前端访问地址:http://localhost:8000
c:前端把数据展示在页面中去
那什么是跨域呢?
前端当前的地址和后端访问的地址有三个中有一个不一样,就叫跨域
a.协议:http[都一样]
b.IP地址192.168.0.1 192.168.0.2 [不一样]
c.端口8080 8000 [不一样]
1.1 跨域获取所有图纸信息
先安装axios包:npm install axios@0.26.1
如何直接运行,会发现拿不到数据,因为我们没有对跨域进行处理
先在setting.py中加入
ini
ALLOWED_HOSTS = ['*',]
然后在manage.py中加入
python
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TestPlatform.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
from django.core.management.commands.runserver import Command as Runserver
Runserver.default_addr = 'localhost' # 修改默认地址
Runserver.default_port = '8000' # 修改默认端口
main()
这样可以保证后端运行都在localhost:8000
我们需要安装一个插件完成跨域
ini
pip install django-cors-headers==3.11.0
安装好后配置:
最后在settings.py中加入
ini
# ============跨域请求=============
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
'http://localhost:8080',
)
运行后会发现可以拿到后端数据了
进行代码优化,把获取的数据放到前端页面上
效果为:
为了友好型,如果加载车成功给一个提示语句
导入
javascript
// 导入ElementPlus
import { ElMessage,ElMessageBox } from 'element-plus'
1.2 优化信息展示
对现实数据条数优化
我们发现拿到的数据现实属于什么传感器,属于什么项目都是id不是我们要的文字,对此我们需要这样处理:
less
'''
@Project :gveInformationSystemBE
@File :serializer.py
@IDE :PyCharm
@Author :HXW
@Date :2023/5/23 15:48
'''
# ===========
from rest_framework import serializers
from DrawingManagementSystem.models import Sensor, Project, Data, Drawing
# ----Sensor序列化类----
class SensorSerialzer(serializers.ModelSerializer):
class Meta:
model = Sensor
fields = "__all__"
# ____Project序列化类____
class ProjectSerialzer(serializers.ModelSerializer):
sensor = SensorSerialzer()
class Meta:
model = Project
fields = "__all__"
# ____Data序列化类____
class DataSerialzer(serializers.ModelSerializer):
project = ProjectSerialzer()
class Meta:
model = Data
fields = "__all__"
# ____Drawing序列化类____
class DrawingSerialzer(serializers.ModelSerializer):
data = DataSerialzer()
class Meta:
model = Drawing
fields = "__all__"
效果为:
表格过长呢?
只需要在后面加:show-overflow-tooltip="true"
ruby
<!-- 2.表格部分 -->
<el-table :data="Data.drawing" border style="width: 100%" :header-cell-style="{ backgroundColor:'#409EFF',color:'#FFF',fontSize:'14px' }">
<el-table-column label="序号" type="index" align="center" width="60" />
<el-table-column prop="material_code" label="物料编号" align="center" width="180" :show-overflow-tooltip="true"/>
<el-table-column prop="drawing_name" label="材料名称" align="center" width="160" />
<el-table-column prop="drawing_spec" label="规格/图纸号" align="center" width="180" :show-overflow-tooltip="true"/>
<el-table-column prop="drawing_page" label="图纸页数" align="center" width="60" />
<el-table-column prop="drawing_client_id" label="客户编号" align="center" width="180" :show-overflow-tooltip="true"/>
<el-table-column prop="drawing_version" label="版本号" align="center" width="70" />
<el-table-column prop="drawing_remark" label="备注" align="center" width="180" :show-overflow-tooltip="true"/>
<el-table-column prop="modified" label="最后上传日期" align="center" width="160" />
<el-table-column label="操作" align="center">
<el-button type="primary" :icon="More" circle size="small"/>
<el-button type="warning" :icon="Edit" circle size="small"/>
<el-button type="danger" :icon="Delete" circle size="small"/>
</el-table-column>
</el-table>
2、axios请求优化(一)
如果每次调用接口都要输入一堆实在是太麻烦了,这里可以进行简化
在src根目录新建api文件如下:
新建utils文化如下:
src\utils\request.ts
javascript
// 导入
import axios from "axios";
// 创建一个Axios的app
const request = axios.create({
baseURL:'http://localhost:8000/DrawingApi/v1/',
timeout:5000
})
// 请求拦截器
// 响应拦截器
// 暴露
export default request
src\api\sensors.ts
typescript
// 导入
import request from "../utils/request";
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
// 获取所有
const getAll = (params:any) => {
// request
return request({
method:'get',
url:'Sensors/',
params
})
}
// 添加
const add = (data:any) => {
// request
return request({
method:'post',
url:'Sensors/',
data
})
}
// 获取单一数据
const getOne = (id:any) => {
// request
return request({
method:'get',
url:'Sensors/${id}/',
})
}
// 修改
const edit = (id:any,data:any) => {
// request
return request({
method:'put',
url:'Sensors/${id}/',
data
})
}
// 删除
const del = (id:any,data:any) => {
// request
return request({
method:'delete',
url:'Sensors/${id}/',
})
}
// 暴露所有
export default{
getAll,getOne,edit,add,del
}
src\api\projects.ts
typescript
// 导入
import request from "../utils/request";
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
// 获取所有
const getAll = (params:any) => {
// request
return request({
method:'get',
url:'Projects/',
params
})
}
// 添加
const add = (data:any) => {
// request
return request({
method:'post',
url:'Projects/',
data
})
}
// 获取单一数据
const getOne = (id:any) => {
// request
return request({
method:'get',
url:'Projects/${id}/',
})
}
// 修改
const edit = (id:any,data:any) => {
// request
return request({
method:'put',
url:'Projects/${id}/',
data
})
}
// 删除
const del = (id:any,data:any) => {
// request
return request({
method:'delete',
url:'Projects/${id}/',
})
}
// 暴露所有
export default{
getAll,getOne,edit,add,del
}
src\api\datas.ts
typescript
// 导入
import request from "../utils/request";
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
// 获取所有
const getAll = (params:any) => {
// request
return request({
method:'get',
url:'Datas/',
params
})
}
// 添加
const add = (data:any) => {
// request
return request({
method:'post',
url:'Datas/',
data
})
}
// 获取单一数据
const getOne = (id:any) => {
// request
return request({
method:'get',
url:'Datas/${id}/',
})
}
// 修改
const edit = (id:any,data:any) => {
// request
return request({
method:'put',
url:'Datas/${id}/',
data
})
}
// 删除
const del = (id:any,data:any) => {
// request
return request({
method:'delete',
url:'Datas/${id}/',
})
}
// 暴露所有
export default{
getAll,getOne,edit,add,del
}
src\api\drawings.ts
typescript
// 导入
import request from "../utils/request";
// RESTful 有(获取所有,添加,获取某一个,修改,删除)
// 获取所有
const getAll = (params:any) => {
// request
return request({
method:'get',
url:'Drawings/',
params
})
}
// 添加
const add = (data:any) => {
// request
return request({
method:'post',
url:'Drawings/',
data
})
}
// 获取单一数据
const getOne = (id:any) => {
// request
return request({
method:'get',
url:'Drawings/${id}/',
})
}
// 修改
const edit = (id:any,data:any) => {
// request
return request({
method:'put',
url:'Drawings/${id}/',
data
})
}
// 删除
const del = (id:any,data:any) => {
// request
return request({
method:'delete',
url:'Drawings/${id}/',
})
}
// 暴露所有
export default{
getAll,getOne,edit,add,del
}
src\api\index.ts
javascript
// 导入所有api
import sensors from "./sensors";
import projects from "./projects";
import datas from "./datas";
import drawings from "./drawings";
// 封装暴露
export default{
sensors,projects,datas,drawings,
}
引用可为:
效果还是一样的:
3、把对应信息填充到下拉框
由于我们api都写好了,那么直接调用就好了:
ini
script区域:
// 获取所有传感器的信息
const getSensors = () => {
return Api.sensors.getAll().then((res)=>{
Data.sensorOptions = res.data;
})
}
// 获取所有项目的信息
const getProjects = () => {
return Api.projects.getAll().then((res)=>{
Data.projectOptions = res.data;
})
}
// 获取所有资料的信息
const getDatas = () => {
return Api.datas.getAll().then((res)=>{
Data.dataOptions = res.data;
})
}
template 区域:
<!-- 1.查询区域 -->
<el-form :inline="true" class="demo-form-inline" style="display: flex">
<el-form-item label="查询条件:">
<el-input v-model="Data.q_str" placeholder="请输入查询条件" clearable/>
</el-form-item>
<el-form-item label="传感器:">
<el-select v-model="Data.sensorSelected" placeholder="请选择传感器" clearable filterable>
<el-option
v-for="item in Data.sensorOptions"
:key="item.id"
:label="item.sensor_name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="项目:">
<el-select v-model="Data.projectSelected" placeholder="请选择项目" clearable filterable>
<el-option
v-for="item in Data.projectOptions"
:key="item.id"
:label="item.project_name"
:value="item.id" />
</el-select>
</el-form-item>
<el-form-item label="资料:">
<el-select v-model="Data.dataSelected" placeholder="请选择资料" clearable filterable>
<el-option
v-for="item in Data.dataOptions"
:key="item.id"
:label="item.data_name"
:value="item.id" />
</el-select>
</el-form-item>
对了 之前表格信息不全 进行补充
ruby
<!-- 2.表格部分 -->
<el-table :data="Data.drawing" border style="width: 100%" :header-cell-style="{ backgroundColor:'#409EFF',color:'#FFF',fontSize:'14px' }">
<el-table-column label="序号" type="index" align="center" width="60" />
<el-table-column prop="material_code" label="物料编号" align="center" width="180" :show-overflow-tooltip="true"/>
<el-table-column prop="drawing_name" label="材料名称" align="center" width="160" />
<el-table-column prop="data.project.sensor.sensor_name" label="所属传感器" align="center" width="80" :show-overflow-tooltip="true"/>
<el-table-column prop="data.project.project_name" label="所属项目" align="center" width="80" :show-overflow-tooltip="true"/>
<el-table-column prop="drawing_spec" label="规格/图纸号" align="center" width="180" :show-overflow-tooltip="true"/>
<el-table-column prop="drawing_page" label="图纸页数" align="center" width="60" />
<el-table-column prop="drawing_client_id" label="客户编号" align="center" width="100" :show-overflow-tooltip="true"/>
<el-table-column prop="drawing_version" label="版本号" align="center" width="70" />
<el-table-column prop="drawing_remark" label="备注" align="center" width="180" :show-overflow-tooltip="true"/>
<el-table-column prop="modified" label="最后上传日期" align="center" width="160" />
<el-table-column label="操作" align="center">
<el-button type="primary" :icon="More" circle size="small"/>
<el-button type="warning" :icon="Edit" circle size="small"/>
<el-button type="danger" :icon="Delete" circle size="small"/>
</el-table-column>
</el-table>
效果为:
4、对树进行数据填充
这边树的处理是前端拼接的,理论上由后端进行处理传给前端,前端按照层级点击后进行加载。但是这里由于项目是我一个人编写,且未来项目其实数据量不会很大。所以我这里还是以项目跑起来为主,后期再优化
scss
// 将数据拼接成树
const getTree = () => {
Promise.all([getSensors(), getProjects(), getDatas()]).then(() => {
// 组合
for(let sensors of Data.sensorOptions){
// 定义需要的结构
var obj = reactive({
value:`${sensors.id}-${sensors.sensor_name}`,
label:sensors.sensor_name,
children:[],
depth: 1
})
// 遍历项目填充obj的children
for(let project of Data.projectOptions){
if(project.sensor.id === sensors.id){
var obj1 = reactive({
value:project.id,
label:project.project_name,
children:[],
depth: 2
});
for(let data of Data.dataOptions){
if(data.project.id === project.id){
obj1.children.push({
value:data.id,
label:data.data_name,
depth: 3
});
}
}
obj.children.push(obj1)
}
}
Data.treeData.push(obj)
}
});
}
// 定义页面加载的时候自动执行的函数
const autoRun = () => {
// 获取所有图纸信息
getData();
// 获取所有传感器的信息
getSensors();
getProjects();
getDatas();
getTree();
}
<!-- 侧边栏 -->
<div class="tree-container">
<el-tree :data="Data.treeData" @node-click="nodeClick"></el-tree>
</div>
效果为:
思考:这里如果通过树进行搜索的话,那我搜索的下拉框其实作用就不大了,且没有层级绑定。
这边暂时不进行修改,为了更好的展示项目知识点,方便今后其他项目需要进行修改。后期系统优化时候,再进行修改。
未完待续。。。