Django后台数据获取展示

​ 续接Django REST Framework,使用Vite构建Vue3的前端项目

1.跨域获取后台接口并展示

  • 安装Axios
npm install axios --save
  • 前端查看后端所有定义的接口
// 访问后端定义的可视化Api接口文档
http://ip:8000/docs/
// 定义的学生类信息
http://ip:8000/api/v1/students/

  • 前端对后端发起请求
// 导入 axios
import axios from 'axios'// 页面一加载便获取axios请求<script>// 获取所有信息const getStudents = () => {// axios请求axios.get('http://192.168.20.110:8000/api/v1/students/').then((res)=>{// 请求成功console.log('成功',res)}).catch((error)=>{// 请求失败console.log('失败',error)})}// 定义页面加载时自动执行的函数const autoRun= () => {// 获取所有信息getStudents() }// 调用自动执行函数执行autoRun() 
</script>
  • 后端配置运行环境

// 或者直接在0.0.0.0:8000下运行
python manage.py runserver 0.0.0.0:8000// 后端开启跨域,安装组件
pip install django-cors-headers
// 注册
INSTALLED_APPS['corsheaders'
]
// 添加到中间件中
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','corsheaders.middleware.CorsMiddleware',# 跨域请求'django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]
# ======跨域配置======
# 后端是否支持对 Cookis访问
CORS_ALLOW_CREDENTIALS = True
# 白名单地址
CORS_ORIGIN_WHITELIST = ('http://192.168.20.110:8080',
)

  • 跨域获取所有信息
// 导入 axios
import axios from 'axios'// 添加信息获取提示
import { ElMessage } from 'element-plus'// 页面一加载便获取axios请求<script>// 获取所有信息const getStudents = () => {// axios请求axios.get('http://192.168.20.110:8000/api/v1/students/').then((res)=>{// 请求成功// console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.countElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})}// 定义页面加载时自动执行的函数const autoRun= () => {// 获取所有信息getStudents() }// 调用自动执行函数执行autoRun() 
</script>

  • 分页优化
<script lang="ts" setup>
import { ref, reactive } from "vue"
import {More,Edit,Delete} from "@element-plus/icons-vue"
import axios from 'axios'
// 添加信息获取提示
import { ElMessage } from 'element-plus'// 定义存储集合
var Data = reactive({// 定义输入的查询条件q_str: ref(""),// 存储从后台获取的所有院系信息FacultyOptions: reactive([{value:1,label:'计算机学院'},{value:2,label:'外语学院'},]),// 存储选择院系后的值FacultySelected: ref(""),// 存储从后台获取的所有专业信息MajorOptions: reactive([{value:1,label:'计算机专业'},{value:2,label:'外语专业'},]),// 存储选择专业后的值MajorSelected: ref(""),// ===表格区域定义====students: reactive([]),// =====分页====// 当前页currentsPage: ref(1),// 每页显示的数据量pageSize: ref(15),// 总数据量所有记录条数total: ref(0),
});// 分页中修改每页的pageSize
const handleSizeChange=(size: any)=>{// 修改记录条数Data.pageSize = size// 重新获取所有信息getStudents()
}// 分页中修改每页的currentsPage
const handleCurrentChange=(page: any)=>{// 修改当前页Data.currentsPage = page// 重新获取所有信息getStudents()
}// ======前后端交互======
// 获取所有信息
const getStudents = () => {// 定义一个集合存储分页参数let params = {page: Data.currentsPage,size: Data.pageSize}// axios请求axios.get('http://192.168.20.110:8000/api/v1/students/',{params:params}).then((res)=>{// 请求成功console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.count// 成功提示ElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})}// 定义页面加载时自动执行的函数const autoRun= () => {// 获取所有信息getStudents() }// 调用自动执行函数执行autoRun() </script>
  • 院系/专业信息展示优化

学生表里只记录了专业的id,专业表里记录了院系的id,要使在学生明细表中展示专业和院系信息则需要在后端序列化专业表和院系表

// serializer.py
# 导入模块
# models中的类与接口转换
from rest_framework import serializers
from studentweb.models import *# 学院序列化类
class FacultySerializer(serializers.ModelSerializer):class Meta:model = Facultyfields = '__all__'# 专业序列化类
class MajorSerializer(serializers.ModelSerializer):# 序列化学院idfaculty = FacultySerializer()class Meta:model = Majorfields = '__all__'# 学生序列化类
class StudentSerializer(serializers.ModelSerializer):# 序列化专业信息major = MajorSerializer()class Meta:model = Studentfields = '__all__'
// 专业的名字:major.name
// 院系的名字:major.faculty.name
{"sno": "950001","major": {"id": 2,"faculty": {"id": 1,"name": "计算机学院"},"name": "计算机网络"},"name": "王晓宇","gender": "男","birthday": "2022-03-01","mobile": "13099881122","email": "wangxiaoyu@qq.com","address": "上海市闵行区春都路88号","image": ""},
  •  表格绑定展示
// 更改前端表格展示数据<el-table-column prop="major.faculty.name" label="院系" align="center" width="120" /><el-table-column prop="major.name" label="专业" align="center" width="120" />
  • 表格过长数据处理
// 过长信息不展示完全使用'...'显示// 标签添加 :show-overflow-tooltip="true"属性

2.Axios模块化请求

  • request脚本实现
// 新建 /src/utils/request.ts
// 封装 axios代码实现模块化// 1.导入
import axios from 'axios'
// 2.创建一个Axios的app
const request = axios.create({// 定义基本 URLbaseURL: 'http://192.168.__.___:8000/api/v1/',// 设置超时timeout: 5000,})// 3.暴露
export default request 
// 添加request.ts配置的axios<script lang="ts" setup>
// 导入request
import request from "../../utils/request";
import { ref, reactive } from "vue"
import {More,Edit,Delete} from "@element-plus/icons-vue"// 添加信息获取提示
import { ElMessage } from 'element-plus'// 定义存储集合
var Data = reactive({// 定义输入的查询条件q_str: ref(""),// 存储从后台获取的所有院系信息FacultyOptions: reactive([{value:1,label:'计算机学院'},{value:2,label:'外语学院'},]),// 存储选择院系后的值FacultySelected: ref(""),// 存储从后台获取的所有专业信息MajorOptions: reactive([{value:1,label:'计算机专业'},{value:2,label:'外语专业'},]),// 存储选择专业后的值MajorSelected: ref(""),// ===表格区域定义====students: reactive([]),// =====分页====// 当前页currentsPage: ref(1),// 每页显示的数据量pageSize: ref(15),// 总数据量所有记录条数total: ref(0),
});// 分页中修改每页的pageSize
const handleSizeChange=(size: any)=>{// 修改记录条数Data.pageSize = size// 重新获取所有信息getStudents()
}// 分页中修改每页的currentsPage
const handleCurrentChange=(page: any)=>{// 修改当前页Data.currentsPage = page// 重新获取所有信息getStudents()
}// ======前后端交互======
// 获取所有信息
const getStudents = () => {// 定义一个集合存储分页参数let params = {page: Data.currentsPage,size: Data.pageSize}// axios请求request.get('students/',{params:params}).then((res)=>{// 请求成功console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.count// 成功提示ElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})}// 定义页面加载时自动执行的函数const autoRun= () => {// 获取所有信息getStudents() }// 调用自动执行函数执行autoRun() </script>
  • Api数据集及请求类型以及url优化 接口实现
// 新建 /src/api/students.ts(majors.ts/facultys.ts)// 导入
import request from "../utils/request";// RESTFUL ---> 6个接口【获取所有,添加,获取某一个,修改,删除】// ====获取所有====
const getAll = (params ?: any) => {// requestreturn request({method: "GET",url: "/students",params,})
}// ====添加====
const add= (data: any) => {// requestreturn request({method: "POST",url: "/students",data,})
}
// ====获取单一数据====
const getOne=(id: any) => {// requestreturn request({method: "GET",url: `/students/${id}`,})
}
// ====修改====
const edit=(id: any, data: any) => {// requestreturn request({method: "PUT",url: `/students/${id}`,data})
}
// ====删除====
const del = (id: any) => {// requestreturn request({method: "DELETE",url: `/students/${id}`,})
}
export default {getAll,add,getOne,edit,del,// 也可以直接在此处定义其他的 api
}
// 新建 index.ts用于导入所有api// 导入所有
import studentApi from "./students"
import majorsApi from "./majors"
import facultysApi from "./facultys"// 封装并发布
export default {studentApi,majorsApi,facultysApi,    
}

// 使用 上述定义的接口<script lang="ts" setup>
import { ref, reactive } from "vue"
import {More,Edit,Delete} from "@element-plus/icons-vue"
// 导入API
import indexApi from '../../api/index'
// 添加信息获取提示
import { ElMessage } from 'element-plus'// 定义存储集合
var Data = reactive({// 定义输入的查询条件q_str: ref(""),// 存储从后台获取的所有院系信息FacultyOptions: reactive([{value:1,label:'计算机学院'},{value:2,label:'外语学院'},]),// 存储选择院系后的值FacultySelected: ref(""),// 存储从后台获取的所有专业信息MajorOptions: reactive([{value:1,label:'计算机专业'},{value:2,label:'外语专业'},]),// 存储选择专业后的值MajorSelected: ref(""),// ===表格区域定义====students: reactive([]),// =====分页====// 当前页currentsPage: ref(1),// 每页显示的数据量pageSize: ref(15),// 总数据量所有记录条数total: ref(0),
});// 分页中修改每页的pageSize
const handleSizeChange=(size: any)=>{// 修改记录条数Data.pageSize = size// 重新获取所有信息getStudents()
}// 分页中修改每页的currentsPage
const handleCurrentChange=(page: any)=>{// 修改当前页Data.currentsPage = page// 重新获取所有信息getStudents()
}// ======前后端交互======
// 获取所有信息
const getStudents = () => {// 定义一个集合存储分页参数let params = {page: Data.currentsPage,size: Data.pageSize}// axios请求indexApi.studentApi.getAll(params).then((res)=>{// 请求成功console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.count// 成功提示ElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})}// 定义页面加载时自动执行的函数const autoRun= () => {// 获取所有信息getStudents() }// 调用自动执行函数执行autoRun() </script><template><!-- 1.顶部查询区域   styple="display: flax;"横向显示--><el-form :inline="true"  class="demo-form-inline"><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.FacultySelected" placeholder="请选择院系"><el-option v-for="item in Data.FacultyOptions":key="item.value":label="item.label":value="item.value" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><!-- 动态获取专业信息 --><el-form-item label="专业"><el-select v-model="Data.MajorSelected" placeholder="请选择专业"><el-option v-for="item in Data.MajorOptions":key="item.value":label="item.label":value="item.value" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><!-- <el-form-item label="Activity time"><el-date-pickertype="date"placeholder="Pick a date"clearable/></el-form-item> --><el-form-item><el-button type="primary"><!-- 引入方法1 --><el-icon><component class="icons" is="Search"></component></el-icon><span>查询</span></el-button><el-button type="primary"><!-- 引入方法2 --><el-icon><Finished /></el-icon><span>全部</span></el-button><el-button type="primary"><el-icon><Pointer /></el-icon><span>添加</span></el-button></el-form-item>
</el-form><!-- 2.表格信息部分 --><el-table :data="Data.students" stripe 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="sno" label="学号" align="center" width="80" /><el-table-column prop="name" label="姓名" align="center" width="80" /><el-table-column prop="gender" label="性别" align="center" width="80"  /><el-table-column prop="birthday" label="出生日期" align="center" width="180" /><el-table-column prop="major.faculty.name" label="院系" align="center" width="120" :show-overflow-tooltip="true"/><el-table-column prop="major.name" label="专业" align="center" width="120" /><el-table-column prop="mobile" label="电话" align="center" width="140" /><el-table-column prop="email" label="Email" align="center" width="180" :show-overflow-tooltip="true" /><el-table-column prop="address" label="地址" align="center" :show-overflow-tooltip="true"/><!-- 按钮区域 --><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><!-- 3.分页 currentPage4当前页 pageSize4每页大小 total记录条数 handleSizeChange改变每页大小 handleCurrentChange改变当前页  --><el-pagination style="margin-top: 28px;"backgroundv-model:current-page="Data.currentsPage"v-model:page-size="Data.pageSize":page-sizes="[10,12,15,17,20,25,40,50]"layout="total, sizes, prev, pager, next, jumper":total="Data.total"@size-change="handleSizeChange"@current-change="handleCurrentChange"/>
</template><style scoped>
.demo-form-inline .el-input {--el-input-width: 220px;
}.demo-form-inline .el-select {--el-select-width: 220px;
}</style>
  • 院系联级下拉框实现
// 1.重新定义FacultyOptions 结构
// 定义存储集合
var Data = reactive({// 存储从后台获取的所有院系信息FacultyOptions: reactive([{ id:"",name:""}, ])
}),
// 定义页面加载时自动执行的函数// 获取所有信息
const getStudents = () => {// 定义一个集合存储分页参数let params = {page: Data.currentsPage,size: Data.pageSize}// axios请求indexApi.studentApi.getAll(params).then((res)=>{// 请求成功console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.count// 成功提示ElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})}// 2.获取所有院系信息
const getFacultys = ()=> {// 请求indexApi.facultysApi.getAll().then((res)=>{// console.log(res.data)Data.FacultyOptions = res.data.results;})}// 3.定义页面加载时自动执行的函数
const autoRun= () => {// 获取所有信息getStudents() // 获取院系填充信息getFacultys()
}// 调用自动执行函数执行
autoRun() 4.更改院系标签值
<!-- 动态获取院系信息  clearable filterable 添加过滤--><el-form-item label="院系"><el-select v-model="Data.FacultySelected" placeholder="请选择院系" clearable filterable><el-option v-for="item in Data.FacultyOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item>
  • 专业联动院系下拉框实现 
<script lang="ts" setup>
import { ref, reactive } from "vue"
import {More,Edit,Delete} from "@element-plus/icons-vue"
// 导入API
import indexApi from '../../api/index'
// 添加信息获取提示
import { ElMessage } from 'element-plus'// 定义存储集合
var Data = reactive({// 定义输入的查询条件q_str: ref(""),// 存储从后台获取的所有院系信息FacultyOptions: reactive([{ id:"",name:""}, ]),// 存储选择院系后的值FacultySelected: ref(""),// 存储从后台获取的所有专业信息MajorOptions: reactive([{id: "",name: ""},]),// 存储选择专业后的值MajorSelected: ref(""),// ======前后端交互======// 获取所有院系信息
const getFacultys = ()=> {// 请求indexApi.facultysApi.getAll().then((res)=>{// console.log(res.data)Data.FacultyOptions = res.data.results;})
};
// 获取院系对应的专业信息
const getMajors = () => {// 准备条件let params = {// http://192.168.20.110:8000/api/v1/majors/?name=&faculty=1name:'',faculty: Data.FacultySelected}// 请求indexApi.majorsApi.getAll(params).then((res)=>{// console.log(res.data.results)Data.MajorOptions = res.data.results;})
};// 定义页面加载时自动执行的函数
const autoRun= () => {// 获取所有信息getStudents() // 获取院系填充信息getFacultys()
}
// 调用自动执行函数执行
autoRun() </script><template><!-- 动态获取院系信息 --><el-form-item label="院系"><el-select v-model="Data.FacultySelected" placeholder="请选择院系" clearable filterable @change="getMajors"><el-option v-for="item in Data.FacultyOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><!-- 动态获取专业信息 --><el-form-item label="专业"><el-select v-model="Data.MajorSelected" placeholder="请选择专业"><el-option v-for="item in Data.MajorOptions":key="item.id":label="item.name":value="item.id" /></el-select></el-form-item><el-form-item><el-button type="primary"><!-- 引入方法1 --><el-icon><component class="icons" is="Search"></component></el-icon><span>查询</span></el-button><el-button type="primary"><!-- 引入方法2 --><el-icon><Finished /></el-icon><span>全部</span></el-button><el-button type="primary"><el-icon><Pointer /></el-icon><span>添加</span></el-button></el-form-item>
</el-form>
</template><style scoped>
.demo-form-inline .el-input {--el-input-width: 220px;
}.demo-form-inline .el-select {--el-select-width: 220px;
}</style>
// 后端注意 filter.py Major筛选类的定义# Major的filter类
class MajorFilter(FilterSet):# 重写支持模糊匹配的字段name = filters.CharFilter(field_name='name', lookup_expr='icontains')class Meta:model = Majorfields = ('name','faculty')
  • 面向对象思维优化Api接口
// 新建 api/apibase.ts 定义基础类// 导入
import request from "../utils/request";export default class Apibase {// 定义属性public name : string;// 构造函数(器)constructor(name : string) {this.name = name;}// 方法public getAll = (params?: any) => {// request请求return request({method: "GET",url: `${this.name}`,params,})}// ====添加====public add= (data: any) => {// requestreturn request({method: "POST",url: `${this.name}`,data,})}// ====获取单一数据====public getOne=(id: any) => {// requestreturn request({method: "GET",url: `${this.name}/${id}`,})}// ====修改====public edit=(id: any, data: any) => {// requestreturn request({method: "PUT",url: `${this.name}/${id}`,data})}// ====删除====public del = (id: any) => {// requestreturn request({method: "DELETE",url: `${this.name}/${id}`,})}
}
// 调用基础类 api/index.ts// 导入基础类
import Apibase from "./apibase"// 实例化对象
let studentApi = new Apibase("students");
let majorsApi = new Apibase("majors");
let facultysApi = new Apibase("facultys");// 封装并发布
export default {studentApi,majorsApi,facultysApi,    
}// 删除/注销 facultys.ts、majors.ts、students.ts
  • 联级信息过滤实现查询和展示全部的功能
// 输入关键字筛选实现// 后端输入筛选字段设置
# 学生视图
class StudentViewSet(ModelViewSet):"""create:创建院系信息retrieve:获取院系信息详情数据update:完整更新院系信息partial_update:部分更新院系信息destroy:删除院系信息list:获取所有院系信息"""queryset = Student.objects.all()serializer_class = StudentSerializer# 分页pagination_class = MyPageNumberPaginationfilter_class = StudentFilter# 指定查找匹配的字段search_fields = ('sno','name','mobile','email','address')// 前端获取所有信息中新增search筛选条件// 获取所有信息
const getStudents = () => {// 定义一个集合存储分页参数let params = {page: Data.currentsPage,size: Data.pageSize,// 一对多,可以匹配多个字段 ?search=...search: Data.q_str}// axios请求indexApi.studentApi.getAll(params).then((res)=>{// 请求成功// console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.count// 成功提示ElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})
};// 绑定点击事件
<el-button type="primary" @click="getStudents"><el-icon><component class="icons" is="Search"></component></el-icon><span>查询</span>
</el-button>
// 点击全部按钮查询实现
// 定义函数
// 点击全部 清楚删选条件
const listAllStudent = () =>{// 清空查询条件Data.q_str = ''// 重新获取所有信息getStudents()
}// 绑定按钮<el-button type="primary" @click="listAllStudent"><el-icon><Finished /></el-icon><span>全部</span>
</el-button>
# 院系筛选条件 http://ip/api/v1/students/?sno=&name=&mobile=&major=&faculty=5# 更改后端代码 filter.pyclass StudentFilter(FilterSet):# 重写支持模糊匹配的字段sno = filters.CharFilter(field_name='sno', lookup_expr='icontains')name = filters.CharFilter(field_name='name', lookup_expr='icontains')mobile = filters.CharFilter(field_name='mobile', lookup_expr='icontains')# 添加专业字段匹配major = filters.CharFilter(field_name='major')# 专业表跳转到学院表faculty = filters.CharFilter(field_name='major__faculty')class Meta:model = Student# 新增专业字段fields = ('sno','name','mobile','major')// 前端绑定
// 获取所有信息
const getStudents = () => {// 定义一个集合存储分页参数let params = {page: Data.currentsPage,size: Data.pageSize,// 一对多,可以匹配多个字段 ?search=...search: Data.q_str,// 添加=====院系字段 提供学院的 key====faculty: Data.FacultySelected,}// axios请求indexApi.studentApi.getAll(params).then((res)=>{// 请求成功// console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.count// 成功提示ElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})
};// 点击全部 清楚删选条件
const listAllStudent = () =>{// 清空查询条件Data.q_str = ''// ======清空院系条件======Data.FacultySelected = ''// 重新获取所有信息getStudents()
}
// 专业信息筛选// 获取所有信息
const getStudents = () => {// 定义一个集合存储分页参数let params = {page: Data.currentsPage,size: Data.pageSize,// 一对多,可以匹配多个字段 ?search=...search: Data.q_str,// 添加院系字段 提供学院的 keyfaculty: Data.FacultySelected,// 添加专业筛选major: Data.MajorSelected}// axios请求indexApi.studentApi.getAll(params).then((res)=>{// 请求成功// console.log('成功',res)// 判断是否成功if (res.status==200){// 成功执行Data.students = res.data.results// 将记录总数绑定到分页的totalData.total = res.data.count// 成功提示ElMessage({message: '数据加载成功!',type: 'success',})}}).catch((error)=>{// 请求失败console.log('失败',error)})
};// 点击全部 清楚删选条件
const listAllStudent = () =>{// 清空查询条件Data.q_str = ''Data.FacultySelected = ''Data.MajorSelected = ''// 重新获取所有信息getStudents()
}
  • 配置Vue实例的全局变量
// 挂载全局对象
// Vue2.0-->Vue.prototype.$api = api 
// Vue3.0-->app.config.globalProperties.api = api
// =====main.ts定义全局变量=====
// 导入所有数据集的 Api
import Apibase from './api/apibase'
// 将 Api挂载到全局的属性
app.config.globalProperties.api = Apibase
// =====全局定义Api使用 info.vue=====
import { ref, reactive, getCurrentInstance } from "vue"
// 获取当前实例
const indexApi = (getCurrentInstance() as any).proxy.api;
  • 请求拦截器和响应拦截器

请求拦截器: 自动添加身份验证的token 


// ====请求拦截器 utils/request.ts=====// ====封装 axios代码实现模块化====
// 1.导入
import axios from 'axios'
// 2.创建一个Axios的app
const request = axios.create({// 定义基本 URLbaseURL: 'http://192.168.20.110:8000/api/v1/',// 设置超时timeout: 5000,})// ====请求拦截器(发请求request)基于上边创建的request====
request.interceptors.request.use((config: any) => {// 获取本地loalstorage中的totenlet token = localStorage.getItem('toten')// 判断是否有tokenif(token) {// 如果有token,就在请求头中添加tokenconfig.headers.common['token'] = token}// 返回return config},(error: any) => {Promise.reject(error);},
);
// ====响应拦截器(反馈response) 基于上边创建的request====
request.interceptors.response.use();
// 3.暴露
export default request // ==========后端配置 settings.py========
CORS_ALLOW_HEADERS = ('token','jwt','accept','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with',
)

响应拦截器: 自动提示所有的请求报错信息

// ====封装 axios代码实现模块化====
// 1.导入
import axios from 'axios'
import {ElMessage} from 'element-plus'
// 2.创建一个Axios的app
const request = axios.create({// 定义基本 URLbaseURL: 'http://192.168.20.110:8000/api/v1/',// 设置超时timeout: 5000,})// ====请求拦截器(发请求request)基于上边创建的request====
request.interceptors.request.use((config: any) => {// 获取本地loalstorage中的totenlet token = localStorage.getItem('toten')// 判断是否有tokenif(token) {// 如果有token,就在请求头中添加tokenconfig.headers.common['token'] = token}// 返回return config},(error: any) => {Promise.reject(error);},
);// ====响应拦截器(反馈response) 基于上边创建的request====
request.interceptors.response.use((response: any) => response,(error: any) => {if (error && error.response) {error.data = {};switch (error.response.status) {case 400:error.data.msg = '错误请求';ElMessage.error(error.data.msg)breakcase 401:error.data.msg = '未授权,请重新登录';ElMessage.error(error.data.msg)breakcase 403:error.data.msg = '拒绝访问';ElMessage.error(error.data.msg)breakcase 404:error.data.msg = '请求错误,未找到该资源';ElMessage.error(error.data.msg)breakcase 405:error.data.msg = '请求方法未允许';ElMessage.error(error.data.msg)breakcase 408:error.data.msg = '请求超时';ElMessage.error(error.data.msg)breakcase 500:error.data.msg = '服务器端出错';ElMessage.error(error.data.msg)breakcase 501:error.data.msg = '网络未实现';ElMessage.error(error.data.msg)breakcase 502:error.data.msg = '网络错误';ElMessage.error(error.data.msg)breakcase 503:error.data.msg = '服务不可用';ElMessage.error(error.data.msg)breakcase 504:error.data.msg = '网络超时';ElMessage.error(error.data.msg)breakcase 505:error.data.msg = 'http版本不支持该请求';ElMessage.error(error.data.msg)breakdefault:error.data.msg = `连接错误${error.response.status}`;ElMessage.error(error.data.msg)}} else {error.data.msg = "连接到服务器失败";ElMessage.error(error.data.msg)}return Promise.reject(error);}
);
// 3.暴露
export default request 

3.信息弹出层的布局和数据填充实现

  • 信息弹出层实现
// ========定义存储集合========
var Data = reactive({// 定义输入的查询条件q_str: ref(""),// 存储从后台获取的所有院系信息FacultyOptions: reactive([{ id:"",name:""}, ]),// 存储选择院系后的值FacultySelected: ref(""),// 存储从后台获取的所有专业信息MajorOptions: reactive([{id: "",name: ""},]),// 存储选择专业后的值MajorSelected: ref(""),// ===表格区域定义====students: reactive([]),// =====分页====// 当前页currentsPage: ref(1),// 每页显示的数据量pageSize: ref(15),// 总数据量所有记录条数total: ref(0),// =====弹出层-----dialogFormVisible: ref(false),
});
// ====弹出层(顶部添加按钮)====
const addStudent = () => {Data.dialogFormVisible = true;
}<!-- 4.弹出层 --><el-dialog v-model="Data.dialogFormVisible" title="学生信息" width="40%"><el-form :inline="true"><el-form-item label="学号:"><el-input placeholder="请输入" /></el-form-item><el-form-item label="姓名:"><el-input placeholder="请输入" /></el-form-item><el-form-item label="性别:" style="width: 20%;"><el-select placeholder="请选择"><el-option label="男" value="shanghai" /><el-option label="女" value="beijing" /></el-select></el-form-item><!-- 动态获取院系信息 --><el-form-item style="width: 32%;" label="院系:"><el-select v-model="Data.FacultySelected" placeholder="请选择院系" clearable filterable @change="getMajors"><el-option v-for="item in Data.FacultyOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><!-- 动态获取专业信息 --><el-form-item style="width: 32%;" label="专业:"><el-select v-model="Data.MajorSelected" placeholder="请选择专业" clearable filterable><el-option v-for="item in Data.MajorOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><el-form-item label="电话:"><el-input placeholder="请输入" /></el-form-item><el-form-item label="邮箱:"><el-input placeholder="请输入" /></el-form-item><!-- 日期 --><el-form-item style="width: 32%;" label="出生日期:"><el-date-pickertype="date"placeholder="请选择日期"clearable/></el-form-item><el-form-item style="width: 57%;" label="家庭住址:"><el-input  type="textarea" /></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button>取消</el-button><el-button>提交</el-button></div></template></el-dialog>

  • 优化弹出层展示实现

// 弹出层定义
// 定义存储集合
var Data = reactive({// =====弹出层-----dialogFormVisible: ref(false),// 定义弹出层标题layerTitle: ref(""),// 定义表单双向绑定的值studentform: reactive({sno: ref(""),name: ref(""),gender: ref(""),birthday: ref(""),faculty: reactive({// 存储从后台获取的所有院系信息FacultyOptions: reactive([{ id:"",name:""}, ]),// 存储选择院系后的值FacultySelected: ref(""),}),major: reactive({// 存储从后台获取的所有专业信息MajorOptions: reactive([{id: "",name: ""},]),// 存储选择专业后的值MajorSelected: ref(""),}),mobile: ref(""),email: ref(""),address: ref(""),})
})// ====弹出层(顶部添加按钮)====
const addStudent = () => {Data.dialogFormVisible = true;// 修改标题Data.layerTitle = '【添加学生信息】'
}// *************************
// 获取所有院系信息
const getFacultysTC = ()=> {// 请求indexApi.facultysApi.getAll().then((res)=>{// console.log(res.data)Data.studentform.faculty.FacultyOptions = res.data.results;})
};
// 获取院系对应的专业信息
const getMajorsTC = () => {// 准备条件let params = {// http://192.168.20.110:8000/api/v1/majors/?name=&faculty=1name:'',faculty: Data.studentform.faculty.FacultySelected}// 请求indexApi.majorsApi.getAll(params).then((res)=>{// console.log(res.data.results)Data.studentform.major.MajorOptions = res.data.results;})
};// 关闭弹出层
const closeLayer = () => {Data.dialogFormVisible = false;
}// 定义页面加载时自动执行的函数
const autoRun= () => {// 获取所有信息getStudents() // 获取院系填充信息getFacultys()// 获取弹出层院系填充信息getFacultysTC()
}
// 调用自动执行函数执行
autoRun() // 动态标题绑定
<!-- 标题 -->
<template #title><div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">{{ Data.layerTitle}}</div>
</template>// 表单数据显示
<!-- 4.弹出层 --><el-dialog v-model="Data.dialogFormVisible" width="40%"><!-- 标题 --><template #title><div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">{{ Data.layerTitle}}</div></template><!--先在form上绑定 Data.studentform  --><el-form v-model="Data.studentform" :inline="true"><!-- 然后在每一个值上进行绑定 --><el-form-item label="学号:"><el-input v-model="Data.studentform.sno" placeholder="请输入" /></el-form-item><el-form-item label="姓名:"><el-input v-model="Data.studentform.name" placeholder="请输入" /></el-form-item><el-form-item label="性别:" style="width: 20%;"><el-select v-model="Data.studentform.gender" placeholder="请选择"><el-option label="男" value="shanghai" /><el-option label="女" value="beijing" /></el-select></el-form-item><!-- 动态获取院系信息 --><el-form-item style="width: 32%;" label="院系:"><el-select v-model="Data.studentform.faculty.FacultySelected" placeholder="请选择院系" clearable filterable @change="getMajorsTC"><el-option v-for="item in Data.studentform.faculty.FacultyOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><!-- 动态获取专业信息 --><el-form-item style="width: 32%;" label="专业:"><el-select v-model="Data.studentform.major.MajorSelected" placeholder="请选择专业" clearable filterable><el-option v-for="item in Data.studentform.major.MajorOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><el-form-item label="电话:"><el-input v-model="Data.studentform.mobile" placeholder="请输入" /></el-form-item><el-form-item label="邮箱:"><el-input v-model="Data.studentform.email" placeholder="请输入" /></el-form-item><!-- 日期 --><el-form-item style="width: 32%;" label="出生日期:"><el-date-pickertype="date"placeholder="请选择日期"clearablev-model="Data.studentform.birthday"/></el-form-item><el-form-item style="width: 57%;" label="家庭住址:"><el-input v-model="Data.studentform.address"  type="textarea" /></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button @click="closeLayer">取消</el-button><el-button>提交</el-button></div></template></el-dialog>
  • 三种状态加载弹出层实现
var Data = reactive({// 弹出层中表单元素是否可编辑定义isView: ref(false), // 是否为查看状态 默认不是sEdit: ref(false), // 是否为编辑状态 默认不是
})// 查看信息
const viewStudent = (row: any) => {Data.dialogFormVisible = true;// 修改标题Data.layerTitle = '【查看学生信息】'// 编辑状态Data.isEdit = false// 查看状态Data.isView = true
}// 编辑信息const editStudent = (row: any) => {Data.dialogFormVisible = true;// 修改标题Data.layerTitle = '【编辑学生信息】'// 编辑状态Data.isEdit = true// 查看状态Data.isView = false
}<!-- 按钮区域 -->
<el-table-column label="操作" align="center"><el-button type="primary" :icon="More" @click="viewStudent" circle size="small"/><el-button type="warning" :icon="Edit" @click="editStudent" circle size="small"/><el-button type="danger" :icon="Delete" circle size="small"/>
</el-table-column><!-- 4.弹出层 --><el-dialog v-model="Data.dialogFormVisible" width="40%"><!-- 标题 --><template #title><div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">{{ Data.layerTitle}}</div></template><!--先在form上绑定 Data.studentform  --><el-form v-model="Data.studentform" :inline="true"><!-- 然后在每一个值上进行绑定 --><el-form-item label="学号:"><!-- 设置字段是否可编辑 :disabled="Data.isEdit || Data.isView" 若一个为 True则输入框即为禁用状态 --><el-input v-model="Data.studentform.sno" :disabled="Data.isEdit || Data.isView" placeholder="请输入" /></el-form-item><el-form-item label="姓名:"><el-input v-model="Data.studentform.name" :disabled="Data.isView" placeholder="请输入" /></el-form-item><el-form-item label="性别:" style="width: 20%;"><el-select v-model="Data.studentform.gender" :disabled="Data.isView" placeholder="请选择"><el-option label="男" value="shanghai" /><el-option label="女" value="beijing" /></el-select></el-form-item><!-- 动态获取院系信息 --><el-form-item style="width: 32%;" label="院系:"><el-select v-model="Data.studentform.faculty.FacultySelected" :disabled="Data.isView" placeholder="请选择院系" clearable filterable @change="getMajorsTC"><el-option v-for="item in Data.studentform.faculty.FacultyOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><!-- 动态获取专业信息 --><el-form-item style="width: 32%;" label="专业:"><el-select v-model="Data.studentform.major.MajorSelected" :disabled="Data.isView" placeholder="请选择专业" clearable filterable><el-option v-for="item in Data.studentform.major.MajorOptions":key="item.id":label="item.name":value="item.id" /><!-- <el-option label="Zone one" value="shanghai" /><el-option label="Zone two" value="beijing" /> --></el-select></el-form-item><el-form-item label="电话:"><el-input v-model="Data.studentform.mobile" :disabled="Data.isView" placeholder="请输入" /></el-form-item><el-form-item label="邮箱:"><el-input v-model="Data.studentform.email" :disabled="Data.isView" placeholder="请输入" /></el-form-item><!-- 日期 --><el-form-item style="width: 32%;" label="出生日期:"><el-date-pickertype="date"placeholder="请选择日期"clearablev-model="Data.studentform.birthday":disabled="Data.isView"/></el-form-item><el-form-item style="width: 57%;" label="家庭住址:"><el-input v-model="Data.studentform.address" :disabled="Data.isView"  type="textarea" /></el-form-item></el-form><template #footer><div class="dialog-footer"><el-button @click="closeLayer">取消</el-button><el-button v-show="!Data.isView">提交</el-button></div></template></el-dialog>
  • 实现填充数据到弹出层
var Data = reactive({// 定义表单双向绑定的值studentform: reactive({sno: ref(""),name: ref(""),gender: ref(""),birthday: ref(""),faculty: ref(""),major: ref(""),mobile: ref(""),email: ref(""),address: ref(""),}),// 弹出层中表单元素是否可编辑定义isView: ref(false), // 是否为查看状态 默认不是isEdit: ref(false), // 是否为编辑状态 默认不是
});// 查看学生信息
const viewStudent = (row: any) => {// 设定标题Data.layerTitle = "【查看学生信息】";// 设为查看Data.isView = true;// 可见Data.dialogFormVisible = true;// 当前行赋值为studentForm -- 深拷贝Data.studentform = JSON.parse(JSON.stringify(row));
};// 编辑学生信息
const editStudent = (row: any) => {// 设定标题Data.layerTitle = "【编辑学生信息】";// 设为编辑Data.isEdit = true;// 可见Data.dialogFormVisible = true;// 当前行赋值为studentForm -- 深拷贝console.log(row)// Data.studentform = rowData.studentform = JSON.parse(JSON.stringify(row));
};// 关闭弹出层
const closeLayer = () => {Data.dialogFormVisible = false;// 编辑和查看设置为FalseData.isEdit = false;Data.isView = false;// 初始化表单Data.studentform.sno = "";Data.studentform.name = "";Data.studentform.gender = "";Data.studentform.birthday = "";Data.studentform.major = "";Data.studentform.faculty = "";Data.studentform.mobile = "";Data.studentform.email = "";Data.studentform.address = "";
}<!-- 按钮区域 -->
<el-table-column label="操作" align="center"><template #default="scope"><el-button type="primary" :icon="More" @click="viewStudent(scope.row)" circle size="small"/><el-button type="warning" :icon="Edit" @click="editStudent(scope.row)" circle size="small"/><el-button type="danger" :icon="Delete" circle size="small"/></template>
</el-table-column><!-- 弹出层 -->
<el-dialog v-model="Data.dialogFormVisible" width="40%" @close="closeLayer"><!-- 标题部分 --><template #title><div style="font-size: 18px; color: #409eff; font-weight: bold; text-align: left">{{ Data.layerTitle }}</div></template><el-form:model="Data.studentform":inline="true"label-width="100px"ref="studentFormRef"><el-form-item label="学号:" prop="sno"><el-inputv-model="Data.studentform.sno":disabled="Data.isEdit || Data.isView":suffix-icon="Edit"placeholder="请输入"/></el-form-item><el-form-item label="姓名:" prop="name"><el-inputv-model="Data.studentform.name":disabled="Data.isView":suffix-icon="Edit"placeholder="请输入"/></el-form-item><el-form-item label="性别:" style="width: 43%;" prop="gender"><el-selectv-model="Data.studentform.gender":disabled="Data.isView"placeholder="请选择"><el-option label="男" value="男" /><el-option label="女" value="女" /></el-select></el-form-item><el-form-item label="出生日期:" prop="birthday" ><el-date-pickerv-model="Data.studentform.birthday"type="date"placeholder="选择日期"style="width: 212px":disabled="Data.isView"value-format="YYYY-MM-DD"></el-date-picker></el-form-item><el-form-item label="电话:" prop="mobile"><el-inputv-model="Data.studentform.mobile":disabled="Data.isView":suffix-icon="Edit"placeholder="请输入"/></el-form-item><el-form-item label="邮箱:" prop="email"><el-inputv-model="Data.studentform.email":disabled="Data.isView":suffix-icon="Edit"placeholder="请输入"/></el-form-item><el-form-item label="家庭住址:" prop="address"><el-inputv-model="Data.studentform.address":suffix-icon="Edit"style="width: 555px":disabled="Data.isView"placeholder="请输入"></el-input></el-form-item></el-form><template #footer><span class="dialog-footer"><el-button type="primary" v-show="!Data.isView">提交</el-button><el-button @click="closeLayer">取消</el-button></span></template></el-dialog>
  • Cascader级联选择器使用
// *******后端取消默认分页 views.py*******# 学院视图
class FacultyViewSet(ModelViewSet):queryset = Faculty.objects.all()serializer_class = FacultySerializer# 取消默认分页pagination_class = None# 专业视图
class MajorViewSet(ModelViewSet):queryset = Major.objects.all()print(queryset)serializer_class = MajorSerializer# 取消默认分页pagination_class = None

// *********前端*********var Data = reactive({
// 弹出层级联选择器定义
layerFacultyMajor: reactive([]),
// 弹出层选中的专业
layerMajorSelected: ref(""),
})// 查看学生信息
const viewStudent = (row: any) => {// 设定标题Data.layerTitle = "【查看学生信息】";// 设为查看Data.isView = true;// 可见Data.dialogFormVisible = true;// 当前行赋值为studentForm -- 深拷贝Data.studentform = JSON.parse(JSON.stringify(row));Data.layerMajorSelected = row.major.id
};// 编辑学生信息
const editStudent = (row: any) => {// 设定标题Data.layerTitle = "【编辑学生信息】";// 设为编辑Data.isEdit = true;// 可见Data.dialogFormVisible = true;// 当前行赋值为studentForm -- 深拷贝console.log(row)// Data.studentform = rowData.studentform = JSON.parse(JSON.stringify(row));Data.layerMajorSelected = row.major.id
};// 关闭弹出层
const closeLayer = () => {Data.dialogFormVisible = false;// 编辑和查看设置为FalseData.isEdit = false;Data.isView = false;// 初始化表单Data.studentform.sno = "";Data.studentform.name = "";Data.studentform.gender = "";Data.studentform.birthday = "";Data.studentform.major = "";Data.studentform.faculty = "";Data.studentform.mobile = "";Data.studentform.email = "";Data.studentform.address = "";// 初始化表单专业的而选择Data.layerMajorSelected = "";
}
// 构建弹出层树状结构的学院和专业
const getTreeMajor = async () =>{// 定义集合let allFacultys = reactive([]);let allMajors = reactive([]);// 获取所有院系await indexApi.facultysApi.getAll().then((res)=>{// console.log(res.data.results)allFacultys = res.data;});// 获取所有专业await indexApi.majorsApi.getAll().then((res)=>{console.log(res)allMajors = res.data;});// 组合数据for (let faculty of allFacultys) {// 定义需要的结构var obj = reactive({value: `${faculty.id}-${faculty.name}`,label: faculty.name,children: [],});// 遍历院系填充obj的childrenfor (let major of allMajors) {// 判断当前专业是否隶属于当前院系if (major.faculty.id === faculty.id) {//添加obj.children.push({value: major.id,label: major.name,});}}// 附加到Data.layerFacultyMajor.push(obj);}
}// 定义页面加载时自动执行的函数
const autoRun= () => {// 获取所有信息getStudents() // 获取院系填充信息getFacultys()// 获取树状结构的学院和专业getTreeMajor()
}
// 调用自动执行函数执行
autoRun() // 定义级联标签
<el-form-item label="学院/专业:">
<el-cascader
v-model="Data.layerMajorSelected"
placeholder="选择专业"
:options="Data.layerFacultyMajor"
filterable
style="width: 555px"
:disabled="Data.isView"/>
</el-form-item>

4.表单校检 

  • 表单提交前校检实现
  // 弹出层表单的验证rules: reactive({sno: [{ required: true, message: "学号不能为空", trigger: "blur" },{pattern: /^[9][5]\d{4}$/,message: "学号必须要是95开头的6位数字",trigger: "blur",},],name: [{ required: true, message: "姓名不能为空", trigger: "blur" },{pattern: /^[\u4e00-\u9fa5]{2,5}$/,message: "姓名需要2-5个汉字",trigger: "blur",},],gender: [{ required: true, message: "性别不能为空", trigger: "blur" }],birthday: [{ required: true, message: "出生日期不能为空", trigger: "blur" },],major: [{ required: true, message: "专业信息不能为空", trigger: "blur" }],mobile: [{ required: true, message: "手机号码不能为空", trigger: "blur" },{pattern: /^[1][3456789]\d{9}$/,message: "手机号码必须要符合规范",trigger: "blur",},],email: [{ required: true, message: "邮箱地址不能为空", trigger: "blur" },{pattern: /^[A-Za-z\d]+([-_.][A-Za-z\d]+)*@([A-Za-z\d]+[-.])+[A-Za-z\d]{2,4}$/,message: "邮箱地址必须要符合规范",trigger: "blur",},],address: [{ required: true, message: "住址不能为空", trigger: "blur" }],}),
  • 应用到指定表单上 
// 标签上绑定rules<el-form :model="Data.studentform" :inline="true" label-width="100px" :rules="Data.rules">// 使用 prop="" 应用在指定字段上
<el-form-item label="学号:" prop="sno"></el-form-item>// 定义表单提交属性 ref="studentFormRef" 
<el-form :model="Data.studentform" :inline="true" label-width="100px" ref="studentFormRef" :rules="Data.rules">// 获取当前的instance 校检规则
const {proxy} = getCurrentInstance() as any// 提交按钮绑定
<el-button type="primary" v-show="!Data.isView" @click="commitLayer">提交</el-button>// 弹出层表单提交
const commitLayer = ()=> {// 提交proxy.$refs.studentFormRef.validate((vilid: boolean)=> {if(vilid){alert('符合要求')}})
}
  • 校检指定信息是否存在
// 校验学号是否存在
const validateSNoExists = (rule: any, value: any, callback: any)=>{// 如果是修改,忽略校验if(Data.isEdit) callback();// 连接Student接口indexApi.studentApi.getAll({sno:value}).then((res)=>{// 判断是否存在if(res.data.count>0){callback(new Error("学号已存在!"))} else {callback()}})
}// 添加自定义规则校检
{validator: validateSNoExists, trigger: 'blur' }// 关闭弹出层中重置表单的校验 
proxy.$refs.studentFormRef.resetFields();

5.实现信息的增删改

  • 信息添加实现
# 后端自定义上传格式
# 自定义上传定义
from rest_framework.response import Response
from rest_framework import status# 学生视图
class StudentViewSet(ModelViewSet):queryset = Student.objects.all()serializer_class = StudentSerializer# 分页pagination_class = MyPageNumberPagination# 指定查找匹配的字段search_fields = ('sno','name','mobile','email','address')# 自定义添加格式def create(self, request, *args, **kwargs):# 接受传递的值rec = request.data# 添加try:Student.objects.create(sno= rec.get('sno'), name=rec.get('name'), gender=rec.get('gender'),birthday=rec.get('birthday'), major_id=rec.get('major'),mobile= rec.get('mobile'), email=rec.get('email'), address=rec.get('address'),image=rec.get('image'))return Response({'msg': '添加成功!'}, status=status.HTTP_201_CREATED)except Exception as e:return Response({'error': '添加学生失败'}, status=status.HTTP_400_BAD_REQUEST)
// 前端定义上传数据格式
// 弹出层表单提交
const commitLayer = () => {// 提交proxy.$refs.studentFormRef.validate((vilid: boolean) => {if (vilid) {// 添加或者修改if(Data.isEdit){// 修改}else{// 添加选择的专业Data.studentform.major = Data.layerMajorSelected[1]// 添加indexApi.studentApi.add(Data.studentform).then((res)=>{// 重新加载数据getStudents()// 关闭弹出层 closeLayer();// 提示添加成功!ElMessage({message:"学生添加成功!",type:'success'})})}}})
}
  • 信息修改实现
# 后端定义def update(self, request, *args, **kwargs):# 接收传递的值rec = request.data# 添加try:Student.objects.filter(pk=kwargs.get('pk')).update(name=rec.get('name'), gender=rec.get('gender'),birthday=rec.get('birthday'), major_id=rec.get('major'),mobile=rec.get('mobile'), email=rec.get('email'),address=rec.get('address'), image=rec.get('image'))return Response({'msg': '修改成功!'}, status=status.HTTP_201_CREATED)except Exception as e:return Response({'error': '修改学生失败'}, status=status.HTTP_400_BAD_REQUEST)
// 前端定义// 弹出层表单提交
const commitLayer = () => {// 提交proxy.$refs.studentFormRef.validate((vilid: boolean) => {if (vilid) {// 判断专业是否修改if (Data.layerMajorSelected[1]){Data.studentform.major = Data.layerMajorSelected[1];} else {Data.studentform.major = Data.layerMajorSelected;}// 添加或者修改if(Data.isEdit){// 修改indexApi.studentApi.edit(Data.studentform.sno, Data.studentform).then((res)=>{if(res.status === 201){// 重新加载数据getStudents();// 关闭弹出层 closeLayer();// 提示添加成功!ElMessage({message:"学生信息修改成功!",type:'success'})}})}else{// 添加选择的专业Data.studentform.major = Data.layerMajorSelected[1]// 添加indexApi.studentApi.add(Data.studentform).then((res)=>{// 重新加载数据getStudents()// 关闭弹出层 closeLayer();// 提示添加成功!ElMessage({message:"学生添加成功!",type:'success'})})}}})
}
  • 信息删除实现
// 实现信息删除
const studentDel=(row:any)=>{let confirmStr = "您确定要删除学生信息【学号:" + row.sno + "\t 姓名:" + row.name + "】信息吗?";ElMessageBox.confirm(confirmStr).then(()=>{// 删除indexApi.studentApi.del(row.sno).then((res)=>{if(res.status === 204){// 重新加载数据getStudents()// 提示删除成功!ElMessage({message:"学生信息删除成功!",type:'success'})}}).catch((error) => {// 请求失败console.log('失败', error)// 提示删除失败ElMessage({message:"学生信息删除失败!",type:'error'})})})
}// 删除按钮点击
<el-button type="danger" :icon="Delete" @click="studentDel(scope.row)" circle size="small" />

6.图片上传实现

  • 图片上传后端接口实现

# 通用上传文件 /apps/utils/upload.py"""
本模板实现文件的上传:图片,视频,excel等
当前的上传任务通过upload_file实现,upload_file中有三个参数,分别为:
1) file --- 提交的文件
2) path --- 存储的子目录
3) type --- 文件命名的类型1 ---- 时间日期 + 随机值2 ---- uuid返回值描述:
成功: status: True, Data: 新写入的文件名
失败:status: False, error:错误描述"""
# =========== 导入模块 ===========
from datetime import datetime
import random
import uuid
from django.conf import settings
import osdef get_file_name_random_date():"""根据日期获取随机值"""filename = datetime.now().strftime("%Y-%m-%d").replace("-", "")filename += str(random.randint(1000, 9999))return filenamedef update_file(file, path:str, type:int):"""提供文件的上传:param file: 要上传的文件:param path: 提供的路径:param type: 随机命名的方式  1-- 时间日期随机值  2-- uuid:return:"""# 定义一个new_name获取新路径new_name = ""# 判断if type == 1:new_name = get_file_name_random_date()elif type ==2:new_name = uuid.uuid4().hex# 拼接路径file_name = settings.MEDIA_ROOT + os.path.sep + path + os.path.sep + new_name + os.path.splitext(file.name)[1]# 开始写入try:f = open(file_name, 'wb')# 分多次写入for i in file.chunks():f.write(i)# 关闭f.close()# 返回return {'status': True, 'data':  new_name + os.path.splitext(file.name)[1] }except Exception as e:return {'status': False, 'error': '文件写入磁盘出现异常'}
# 在原有的接口定义中添加自定义接口# 1.导入模块
from rest_framework.decorators import action
from utils import upload# 2.在student视图下定义 upload函数
@action(methods=['post'], detail=False)
def upload(self,request, *args, **kwargs):# 接受前台传递的文件rev_file = request.FILES.get('file')# 判断是否粗壮乃if not rev_file:return Response(status=status.HTTP_400_BAD_REQUEST)# 调用res = upload.update_file(rev_file,'images', 2)# 返回return Response(res)
  • 上传图片功能添加到 API
// 对于自定义新增接口,前端新建api接口处理// 某一类新增字段import Apibase from "./apibase";
import request from "../utils/request";// 继承类
export default class studentApi extends Apibase {// 构造器constructor(name: string) {super(name);}public upload = (data:any)=>{return request({method: 'post',url: `${this.name}/upload/`,data})}
}
  • 图片上传功能实现 
const baseURL = 'http://192.168.20.110:8000/media/image/'
// ==== 头像的上传 ==
const uploadStudentImage = (file:any)=>{// ==== 文件在axios中一般封装在formdata类中// 1. 定义formData类let fileReq = new FormData();// 2. 把文件装在formData的容器中fileReq.append('file', file.file);// 请求 indexApi.studentApi.upload(fileReq).then((res)=>{Data.studentform.image =  baseURL + res.data.data;})
}const handleAvatarSuccess =() =>{// 上传成功的回调
}const beforeAvatarUpload=() =>{// 上传前的的回调
}<!-- 图片的上传和展示 --><el-uploadclass="avatar-uploader":show-file-list="false":http-request="uploadStudentImage":on-success="handleAvatarSuccess":before-upload="beforeAvatarUpload"style="margin: 20px auto"><img v-if="Data.studentform.image" :src="Data.studentform.image" class="avatar" /><el-icon v-else class="avatar-uploader-icon"><plus /></el-icon></el-upload>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/402594.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu下交叉编译器工具链的安装方法

本篇文章记录Ubuntu下交叉编译器工具链的安装方法。 目录 一、交叉编译器 1、交叉编译器简介 2、获取交叉编译器 3、安装交叉编译器 4、安装相关库 二、结语 一、交叉编译器 1、交叉编译器简介 交叉编译器是一种编译器&#xff0c;它在一种平台上运行&#xff0c;但生成…

如何获取VS Code扩展的版本更新信息

获取VS Code 扩展的版本更新的需求 因为企业内部有架设私有扩展管理器的要求&#xff0c;但是对于一些官方市场的插件&#xff0c;希望可以自动获取这些扩展的更新并上传至私有扩展管理器。于是就有了本篇介绍的需求&#xff1a; 通过API的方式获取VS Code 扩展的更新。 关于…

HarmonyOS Next 系列之列表下拉刷新和触底加载更多数据实现(十一)

系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现&#xff08;一&#xff09; HarmonyOS Next 系列之验证码输入组件实现&#xff08;二&#xff09; HarmonyOS Next 系列之底部标签栏TabBar实现&#xff08;三&#xff09; HarmonyOS Next 系列之HTTP请求封装和Token…

STM32入门开发操作记录(九)——外部时钟定时器

目录 一、项目准备1. 工程模板2. 器件接线 二、外部时钟1. 端口复用2. 流程示意 三、定时器模块Timer.cTimer.h 四、遮光计数 一、项目准备 1. 工程模板 本篇项目所用模板包含以下模块&#xff0c;声明函数见头文件&#xff0c;模块添加和函数功能详见往期记录。   2. 器件…

Python之格式化输出

格式化输出 方法一&#xff1a;用%方法二&#xff1a;用format()函数设置输出的内容的宽度和小数位数 方法一&#xff1a;用% 直接用print()函数对字符串进行输出&#xff0c;是没有进行格式化控制的。 格式化&#xff0c;是对输出内容的显示方式进行设置。 首先&#xff0c;要…

小程序滑动单元格

项目场景&#xff1a;小程序用户管理列表&#xff0c;通过单元格滑动实现“密码重置”、“删除”功能。 技术框架&#xff1a;uniapp、uview3、ts 效果如下&#xff1a; 前端页面&#xff1a; <template><view class"fui-wrap"><view class"f…

Spring Boot 的Web开发

Spring Boot 的Web开发 一、 静态资源映射规则 总结&#xff1a; 只要静态资源放在类路径下&#xff1a; called /static (or /public or /resources or /METAINF/resources 访问 &#xff1a; 当前项目根路径/ 静态资源名 二、 enjoy模板引擎 Enjoy模板引擎是一个轻量级的…

数据结构-常见的七大排序

上节中我们学习了七大排序中的五种(插入排序、希尔排序、堆排序、选择排序、交换排序) 数据结构-常见的七大排序-CSDN博客 这节我们将要学习快速排序(hoare、指针法、挖洞法(快排的延伸)、快速排序非递归(栈)) 1.快速排序 1.1 hoare法 1.1思路 1.选出一个key&#xff0c;一…

浅看MySQL数据库

有这么一句话&#xff1a;“一个不会数据库的程序员不是合格的程序员”。有点夸张&#xff0c;但是确是如此。透彻学习数据库是要学习好多知识&#xff0c;需要学的东西也是偏难的。我们今天来看数据库MySQL的一些简单基础东西&#xff0c;跟着小编一起来看一下吧。 什么是数据…

Windows 11环境下安装uwsgi的步骤和方法

正在用Django做个小网站&#xff0c;经常要用runserver启动服务观察效果&#xff0c;很不方便&#xff0c;就想装个uwsgi&#xff0c;让服务总是在后台运行&#xff0c;免得切换。上网一查发现&#xff0c;在windows下安装uwsgi不是一件简单的事情&#xff0c;很多人在尝试之后…

Python | Leetcode Python题解之第338题比特位计数

题目&#xff1a; 题解&#xff1a; class Solution:def countBits(self, n: int) -> List[int]:bits [0]for i in range(1, n 1):bits.append(bits[i & (i - 1)] 1)return bits

Spring Web MVC入门(下)

1. 响应 1.1 返回静态页面 创建前端页面&#xff0c;如下图所示&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Index页面</title> </head> <body>Hello,Spring MVC…

设计模式21-组合模式

设计模式21-组合模式&#xff08;Composite Pattern&#xff09; 写在前面 动机定义与结构定义结构主要类及其关系 C代码推导优缺点应用场景总结补充叶子节点不重载这三个方法叶子节点重载这三个方法结论 写在前面 数据结构模式 常常有一些组件在内部具有特定的数据结构。如何…

CVPR2023《DNF: Decouple and Feedback Network for Seeing in the Dark》暗光图像增强论文阅读笔记

相关链接 论文链接 https://openaccess.thecvf.com/content/CVPR2023/papers/Jin_DNF_Decouple_and_Feedback_Network_for_Seeing_in_the_Dark_CVPR_2023_paper.pdf 代码链接 https://github.com/Srameo/DNF 摘要 RAW数据的独特属性在低光照图像增强方面展现出巨大潜力。…

使用RKNN在Orange Pi 5 (RK3588s) 上部署推理PPO深度学习模型

文章目录 一、前言1️⃣、Orange Pi 是什么&#xff1f;2️⃣、PPO 是什么&#xff1f;3️⃣、RKNN 是什么&#xff1f;3️⃣、ONNX 是什么&#xff1f; 二、项目简介三、部署流程1️⃣、PPO 网络结构2️⃣、PPO 输出模型&#xff0c;模型转换&#xff0c;以及对比检查3️⃣、.…

ECMAScript6语法:默认参数和rest参数

1、默认参数 默认参数即在定义函数的参数列表中指定了默认值的参数。在 ES5 中&#xff0c;并没有提供在参数列表中指定参数默认值的语法&#xff0c;要想为函数的参数指定默认值&#xff0c;只能在函数体中实现&#xff0c;示例代码如下&#xff1a; function table(width, …

【性能优化】使用Perfetto定位应用启动性能的瓶颈

Android应用启动优化相关的文章已经有很多人都写过了&#xff0c;但是主要都是聚焦在&#xff0c;为了启动性能都做了哪些改动上&#xff0c;少见有文章会说应该如何分析、识别应用的启动性能。 本篇文章将会结合我个人对Perfetto的实际使用经历&#xff0c;讲解车载应用的启动…

前端post传入拿到数据,后端报null,并且能够添加或者编辑成功

检查conterller层注解接到实体类的注解是不是没加&#xff08; RequestBody &#xff09; 后端&#xff1a; 前端&#xff1a; 那么就看注解&#xff0c;因为contrller层有个接值注解&#xff08; RequestBody &#xff09;

MySQL基础练习题44-只出现一次的最大数字

目录 题目 情况一 准备数据 分析数据 情况二 准备数据 实现一 题目 单一数字 是在 MyNumbers 表中只出现一次的数字。 找出最大的 单一数字 。如果不存在 单一数字 &#xff0c;则返回 null 。 情况一 准备数据 ## 创建库 create database db; use db;## 创建表 Cre…

代码随想录算法训练营Day42||Leetcode300.最长递增子序列 、 674. 最长连续递增序列 、 718. 最长重复子数组

一、最长递增子序列 简单&#xff0c;只不过返回值不是dp数组最后一个元素了&#xff0c;自己做出来AC了 class Solution { public:int lengthOfLIS(vector<int>& nums) {vector<int>dp(nums.size()1,1);for(int i1;i<nums.size();i){for(int ji-1;j>0…