持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
Python环境没有的,请自行安装,本教程采用的是python 3.9。
Django官网 https://www.djangoproject.com/
Node环境没有的,请自行安装,本教程采用的是node v17.6.0。
首先来解决的上章遗留的问题,如何在DRF中自定义接口。其实直接使用Django的方案来编写接口一样可以达到目的,但是从《Django如何快速开发RESTful风格的接口?》中源码分析部分可以知道,DRF为开发接口提供了更方便的能力,因此本章还是采用DRF的方案来自定义接口。
DRF中自定义接口
这个接口的主要功能是在查询分类时,同时查询接口列表。
- 首先在后端项目
main/views.py中定义一个新的接口继承DRF的APIView。然后定义get方法用来处理get请求。
class CategoryApiView(APIView):
def get(self,request):
pass
- 然后编写逻辑部分
- 如果没有请求参数,即查询没有父分类的分类列表和没有分类的接口列表
- 如果存在请求参数category,即查询有父分类category的分类列表和有分类category的接口列表
class CategoryApiView(APIView):
def get(self, request):
category = None
if "category" in request.GET:
category = request.GET['category']
if category:
query_set = Category.objects.filter(parent_category=category)
category_data = CategorySerializer(query_set, many=True).data
query_set = Api.objects.filter(category=category)
api_data = ApiSerializer(query_set, many=True).data
else:
query_set = Category.objects.filter(parent_category__isnull=True)
category_data = CategorySerializer(query_set, many=True).data
query_set = Api.objects.filter(category__isnull=True)
api_data = ApiSerializer(query_set, many=True).data
return Response(category_data + api_data)
- 在
main/urls.py中定义接口路由
urlpatterns = [
...
path('categorie_apis/', CategoryApiView.as_view())
]
重启项目,查看swagger页面,可以看到新增了一个接口。
后端项目定义完成后,接下来就是前端调用,有两个地方需要进行替换:
- 第一个地方是进入接口管理页面,需要调用接口查询没有一级分类列表和没有分类的接口列表
const queryCategories = (parent_category) => {
// listCategoryApi(parent_category).then((res) => {
// treeData.value = res;
// });
listCategoryApiApi(parent_category).then((res) => {
treeData.value = res;
});
};
重启前端项目,刷新页面,可以看到一级分类以及没有分类的接口都被查询出来了。
- 第二个地方是点击树形结构进行加载,需要将节点ID作为查询参数,调用接口查询指定分类ID下的分类列表和接口列表。
const loadData = (treeNode) => {
return new Promise((resolve) => {
if (treeNode.dataRef.children) {
resolve();
return;
}
if (treeNode.dataRef.type === "collection") {
// 分类下查询子分类和接口
// listCategoryApi(treeNode.dataRef.id).then((res) => {
// let children = res;
// listApiApi(treeNode.dataRef.id).then((res) => {
// children = children.concat(res);
// treeNode.dataRef.children = children;
// treeData.value = [...treeData.value];
// resolve();
// });
// });
listCategoryApiApi(treeNode.dataRef.id).then((res) => {
treeNode.dataRef.children = res;
treeData.value = [...treeData.value];
resolve();
});
} else {
// TODO:接口需要查询用例
resolve();
}
});
};
重启前端项目,刷新页面,点击「分类一」的展开按钮,可以看到子分类和分类下的接口都被查询出来了。
接口管理模块开发(五)
上节已经完成了在分类下新增不带参数的GET请求,并且保存成功,本节将完成在分类下新增带参数的GET请求(包括请求参数和请求头)。
前端组件完善
前面我们定义了TableForm组件,将ATable进行了封装。
存在一个问题是当没有参数时,没有新增按钮,因此需要对于
TableForm组件中的ATable再次进行改造,将无数据时的样式替换掉。
请求参数和请求头保存
组件完善后,首先来处理请求参数和请求头,因为请求参数和请求头都是单独的子组件,在页面上填写的数据也都是保存在子组件的变量中,因此点击父组件【Save】时,父组件要先获取到子组件的值。
- 在
ApiHeader定义一个方法,用于返回initData,并且将方法暴露出来供父组件使用。
<template>
<div class="api-header">
<table-form :initData="initData"></table-form>
</div>
</template>
<script setup>
import { ref, defineExpose } from "vue";
import TableForm from "@/components/TableForm.vue";
const initData = ref([]);
const getData = () => {
return initData.value;
};
// 暴露方法,以供父组件进行调用
defineExpose({
getData,
});
</script>
- 在
ApiListContent中引用子组件ApiHeader时,子组件定义ref属性,并且进行变量声明。
- 点击
ApiListContent中的【Save】按钮时,通过定义的ref变量调用ApiHeader的方法获取数据。
const saveApi = () => {
if (props.category_id !== "") {
formState.value.category = props.category_id;
}
// 获取请求头
if (apiHeader.value) {
formState.value.headers = JSON.stringify(apiHeader.value.getData());
}
addApiApi(formState.value).then(() => {
message.success("保存成功");
});
};
获取请求参数和请求头是同样的操作,将不再赘述。
重启项目,刷新页面,在分类一下选择新增接口,填写接口的请求信息,点击【Save】按钮。可以看到接口请求中已经有请求参数和请求头。
检查数据库可以看到数据已经保存成功。
本章到这里就结束来,下章接着讲带请求体的POST请求如何保存。