drf之路由层

简介

当我们使用了ModelViewSet配置视图层之后,需要在as_view中定义对应字典,如下:

urlpatterns = [
    path('book/', views.BookView.as_view({'get': 'list', 'post': 'create'})),
    path('book/<int:pk>/', views.BookView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})),
]

上面的配置方法非常麻烦,想一下,如果我们有多个接口,多个路由,配置起来会非常复杂,所以drf提供了一个方法,可以自动生成路由

原理

自动生成路由的本质就是自动做映射,映射关系如下:

           get    --->  list
           get    --->  retrieve
           put    --->  update
           post   --->  create
           delete --->  destory

所以,使用默认的自动化生成路由的前提是(如果未定义action装饰器)

  1. 改写了as_view方法,也就是继承了ViewSetMixin
  2. 需要有list/retrieve/update/create/destory中的一个或多个方法,也就是继承了9个视图子类
  3. 也可以使用GenericAPIView加5个试图扩展类,再配合ViewSetMixin才能生成
  • 九个视图子类如下
视图子类 说明
ListAPIView 查询所有数据
CreateAPIView 新增一条数据
ListCreateAPIView 查询所有数据+新增一条数据
RetrieveAPIView 查询一条数据
DestroyAPIView 删除数据
UpdateAPIView 修改数据
RetrieveUpdateAPIView 查询一条数据+修改数据
RetrieveDestroyAPIView 查询一条数据+删除数据
RetrieveUpdateDestroyAPIView 查询一条数据+修改数据+删除数据
  • 五个视图扩展类如下
名称 说明 方法
ListModelMixin 查询所有数据 list
RetrieveModelMixin 查询单条数据 retrieve
CreateModelMixin 新增一条数据 create
UpdateModelMixin 修改一条数据 update
DestroyModelMixin 删除一条数据 destroy

部分关系图

image

  • 其它关系见下表
名称 关系 说明
ViewSetMixin 重写了as_view方法,只要继承它,就需要改变路由的写法,对应映射关系 只是重写了as_view方法,其它功能需要继承别的视图类使用,比如与数据库交互,比如序列化需要与APIView使用(它俩搭配就是ViewSet)
ViewSet 继承了ViewSetMixin和APIView 它继承的两个类都未定义与数据库交互的内容,如果未来的接口不需要与数据库交互,就继承这个类
GenericViewSet 继承了ViewSetMixin和GenericAPIView 由于GenericAPIView定义了与数据库交互的方法,所以未来如果要跟数据库作交互就继承这个类
ModelViewSet 继承5个视图扩展类加ViewSetMixin加GenericAPIView 与GenericViewSet不同的是,它提供了一些通用的视图方法,不可以自定义get/put等映射关系,而GenericViewSet则可以。可以参照下面的ModelViewSet中的对应put/get等关系对应表
ReadOnlyModelViewSet 继承2个视图扩展类、ViewSetMixin、GenericAPIView 与ModelViewSet相同,但只提供查询接口

自动生成路由

首先,需要在视图类中使用ModelViewSet,因为自动生成路由会把自动生成与ModelViewSet中的方法的对应的关系。

from django.contrib import admin
from django.urls import path, include
from app01 import views

# 第一步,导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter

# 第二步,实例化对象
router = SimpleRouter()   # 不会生成根路由
或
router = DefaultRouter()  # 会生成根路由
# 第三步,注册路由
    # 第一个参数books:参数路径,与就是前端访问的时候的路由,但是不带最后的斜杠符咒("/")
    # 第二个参数views.BookView:是对应的视图类
    # 第三个参数books:路由的别名,一般与路由相同
router.register('book', views.BookView, 'book')

# 下面的是django自带的路由,不需要动
urlpatterns = [
    path('admin/', admin.site.urls),
]

# 第四步,在urlpatterns(django自动生成的)中注册,有两种方法
# 方法一:
urlpatterns += router.urls
# 方法二:使用include方法,使用较多,但需要在from django.urls import path, include多导一个include
# 注意这个方法需要改写urlpatterns
urlpatterns = [
    path('admin/', admin.site.urls),
    # 用这种方法的定制路由更文件一些,这时浏览器访问的就是http://127.0.0.1/api/v1/book/
    path('api/v1/', include(router.urls))
]

SimpleRouter与DefaultRouter的区别

在Django Rest Framework(DRF)中,SimpleRouter和DefaultRouter是两种不同的路由器类型。

SimpleRouter是一种简单的路由器,它只会为ViewSet中自定义的操作生成URL,例如你的ViewSet中定义了名为latest的操作,则SimpleRouter只会为latest生成URL。

DefaultRouter是一种全面的路由器。它为ViewSet中所有标准操作(如list、retrieve、update、create等)生成URL,并为自定义操作生成名称。它还为所配置的API浏览器提供了根URL。

如果你想获得一个简单的API,只有少量自定义操作,那么使用SimpleRouter会比较方便,并且可以通过手动添加URL来自定义路由。而如果你需要完整的API,包括标准操作和自定义操作,那么使用DefaultRouter会更加方便,并且能够快速自动生成URL。

简单来说,SimpleRouter比DefaultRouter自由度更高,而DefaultRouter比SimpleRouter更加全面。根据实际情况选择合适的路由器更为重要。

action装饰器自定义路由

根据上文,自动化生成路由时,函数需要把get/post等请求转为list、retrieve等方法,但有时,我们需要把get请求换为更加贴合业务实际情况的方法,这时就需要action装饰器了。
action可以让你可以在视图集(ViewSets)中添加自定义的API端点,以实现各种复杂的API操作。

语法

# 在函数上进行定义
@action(methods=['GET','POST'...], detail=False, url_path='xxx')
# methods 表示此函数接收的请求方式,如GET/POST/DELETE/PUT等,可以定义多个
# detail 表示是否使用主键值,如果等于True,访问路径为:http://192.168.1.1:8000/xxx/12/,相反如果是False,访问路径为:http://192.168.1.1:8000/xxx/
# 也就是当detail=True时的路由相当于path('xxx/<int:pk>', views.xxx.as_view()),而函数也需要有个PK参数接收
# url_path 表示访问地址,不配置此参数默认以方法名命名
# url_name 用作反向解析使用

示例

  • views.py
from rest_framework.decorators import action
from rest_framework.response import Response

class TestView(ViewSet):
    @action(methods=['GET'], detail=False, url_path='data_test', url_name='data_test')
    def data_test(self, request):
        data = request.query_params.get('data')
        print(data)
        return Response({'code': 100, 'msg': '成功'})

# 如果detail=True,函数需要有个pk需要接收
class TestView(ViewSet):
    @action(methods=['GET'], detail=True, url_path='data_test', url_name='data_test')
    def data_test(self, request, pk):
        data = request.query_params.get('data')
        print(data)
        return Response({'code': 100, 'msg': '成功'})
  • urls.py
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('register_test', views.TestView, 'register_test')
# 当action中的detail=False时,访问的地址为:http://127.0.0.1:8000/ap1/v1/register_test/data_test
# 当action中的detail=True时,访问的地址为:http://127.0.0.1:8000/ap1/v1/register_test/123/data_test
# 也就是当action中的detail=True时,需要传一个主键,views.py中的函数也需额外配置一个参数pk
urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/v1/', include(router.urls))
]

http://ip:port/路由中的path/router.register中的命名/url_path的命名/主键

如:
查询所有:http://127.0.0.1:8000/api/v1/register_test/data_test/
查询一条:http://127.0.0.1:8000/api/v1/register_test/data_test/1/
新增一条:http://127.0.0.1:8000/api/v1/register_test/data_test/ 发送post请求
修改一条:http://127.0.0.1:8000/api/v1/register_test/data_test/1/ 发送PUT请求
删除一条:http://127.0.0.1:8000/api/v1/register_test/data_test/1/ 发送DELETE请求

posted @   树苗叶子  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏
点击右上角即可分享
微信分享提示