一步步完整搭建一个图纸管理系统(Django+Vue3)——3、前后端交互

前言: 网上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>

效果为:

思考:这里如果通过树进行搜索的话,那我搜索的下拉框其实作用就不大了,且没有层级绑定。

这边暂时不进行修改,为了更好的展示项目知识点,方便今后其他项目需要进行修改。后期系统优化时候,再进行修改。

未完待续。。。

相关推荐
崔庆才丨静觅27 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX1 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法2 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端