本文根据datawhale开源Djiango后端开发入门( https://github.com/Joe-2002/sweettalk-django4.2 )Task05:路由组件及自定义函数(@action)做的学习笔记
一、学习目标
Django-rest 是 django web 框架的一个插件,透过Django REST framework( DRF ) 建立 REST API 非常方便快速。这里学习该框架的Router路由配置和测试。
二、Router路由功能及使用
此部分内容参考datawhale开源Djiango后端开发入门以及另一篇博客网址:http://t.csdn.cn/CeD15
1 URL格式
REST framework提供了两个router:SimpleRouter,DefaultRouter。路由Router形成URL格式如下:
(1) SimpleRouter
|
(2)DefaultRouter
|
与SimpleRouter相比,DefaultRouter会多附带一个默认的API视图,返回一个包含所有列表视图的超链接响应数据。
2 配置流程
(1) 创建Router对象
导包
from rest_framework import routers
创建对象,用于生成路由
router = routers.SimpleRouter()
或者:router = routers.DefaultRouter()
(2)注册视图集
# 将视图集注册到路由器上,字符串里的是URL路径的前缀
router.register(prefix(路由前缀), viewset(视图集), base_name(路由名称的前缀))
如:router.register('GoodsCategory', GoodsCategoryViewSet,base_name='goodscategoryok')
或者router.register('GoodsCategory', GoodsCategoryViewSet,base_name='goodscategoryok')
(3)路由映射表
两种方式书写方式:
urlpatterns = […
]
或 urlpatterns = [
url(r'^', include(router.urls))
]
三、URL映射方式
在view.py中,有APIView或其子类以及Viewset两类模块抽象,映射方式有一些差别。下面分别描述:
1 ViewSets视图集
REST框架包括用于处理ViewSets的抽象,允许开发人员只需要在路由器注册相应的视图集就可使Router类自动操作。
“ @action 装饰器”用于在 ViewSet 中创建自定义动作(custom action),为 ViewSet 提供了更灵活应用且 @action 只在ViewSet视图集中生效。视图集中附加action装饰器可接收两个参数:(1)methods: 声明该action对应的请求方式.(2)detail: True/False声明该action的路径是否是action对应的请求方式。示例如下:
view.py
class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
@action(methods=['get'], detail=False)
def latest(self, request):
...
@action(methods=['put'], detail=True)
def read(self, request, pk):
......
2 APIView或其子类
APIView不是ViewSet的子类,不支持@action,需要单独设置。映射方式包括自动映射或指定映射URL的两种。
(1) 根据url请求,Django自动将请求映射到对应的APIView方法上:
urls.py:
url(r'^example/$', ExampleView.as_view(), name='example')
view.py:
class ExampleView(APIView):
def get(self, request):
...
def post(self, request):
...
(2)使用URL名称关键字参数来明确指定所调用的方法。如:
urls.py:
url(r'^example/get/$', ExampleView.as_view(name='get'), name='example-get')
url(r'^example/post/$', ExampleView.as_view(name='post'), name='example-post')
view.py:
class ExampleView(APIView):
name= 'get'
def get(self, request):
...
name = 'post'
def post(self, request):
. ..
四 应用举例
1 任务需求
将 modelviewset视图集和apiview类实现基于DefaultRouter的路径配置,并实现可视化输出。
为此,临时制作了两个数据表已合并且存放到数据库中(1)分类表:书籍、电影和音乐。(2)明细表,其中每类对应两条明细。表内容如下:
(1)分类表
|
(2)明细表
|
2 编程思路
- 设定已经在models.py中创立好数据表并已有数据
- view.py文件编写,确定映射的名。(功能中尽量用到task03和tank04的功能函数)
- urls.py文件编写,确定路由生成和映射方式。
- 运行并实现。
3 代码实现
以下程序代码来自 https://github.com/Joe-2002/sweettalk-django4.2开源资料,并根据实际数据表数据和功能需求做了细微的适当修改
view.py
导包
from django.shortcuts import render
from rest_framework.response import Response
from .models import *
from rest_framework.decorators import api_view
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from .serializer import *
from rest_framework.decorators import action
from django.db.models import Q
from rest_framework.viewsets import ModelViewSet
#modelviewset
class GoodsCategoryViewSet(ModelViewSet): # 指定查询集(用到的数据)
queryset = GoodsCategory.objects.all() # 指定查询集用到的序列化容器
serializer_class = GoodsCategorySerilizer
@action(detail=False, methods=['get'])
def latest(self, request):
latest_obj = GoodsCategory.objects.latest('id')
print(latest_obj)
print(serializer.data)
return Response("hello 你调用了自定义的函数")
#apiview
class GetGoods(APIView):
def get(self, request):
if request.method=='post':
data=request.data.get('分类名字')
elif request.method=='GET':
data = request.query_params.get('分类名字')
goods_category = get_object_or_404(GoodsCategory, name=data)
if goods.exists():
goods = Goods.objects.filter(category=goods_category)
data = Goods.objects.all()
serializer = GoodsSerializer(instance=data, many=True)
print(serializer.data)
return Response({"status": "已存在", "goods_category": data}, status=200)
else:
return Response({"status": "不存在" ,"goods_category": data}, status=404)
urls.py
from django.contrib import admin
from django.urls import path
from apps.sxqapp03.views import *
from django.urls import include
from rest_framework import routers
router = routers.DefaultRouter() # 创建DefaultRouter对象
router.register('GoodsCategory', GoodsCategoryViewSet)# 将视图集注册到路由器上
urlpatterns = [
path('admin/', admin.site.urls),
path('getgoods/', GetGoods.as_view()),
]
urlpatterns += router.urls # 把生成的url 添加到项目的url配置中
4 运行测试
(1)GoodsCategoryViewSet(ModelViewSet)测试
- 不指定@action函数名
|
- 2)指定@action函数名
|
models.py模块修改
class GetGoods(APIView):
def get(self, request):
if request.method=='post':
data = request.data.get('分类名字')
elif request.method=='GET':
data = request.query_params.get('分类名字')
goods = Goods.objects.all()
if goods.exists():
goods = Goods.objects.filter(category_id='1') #category_id属于书籍类**加粗样式**
serializer = GoodsSerializer(goods, many=True) # 请确保导入合适的序列化器
print(serializer.data)
return Response(serializer.data)
else:
return Response({"status": "不存在" ,"goods_category": data}, status=404)
运行后,得到的测试结果如下:
|
可见,输出结果和预期一致,功能实现。