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装饰器)
- 改写了as_view方法,也就是继承了ViewSetMixin
- 需要有list/retrieve/update/create/destory中的一个或多个方法,也就是继承了9个视图子类
- 也可以使用GenericAPIView加5个试图扩展类,再配合ViewSetMixin才能生成
- 九个视图子类如下
视图子类 | 说明 |
---|---|
ListAPIView | 查询所有数据 |
CreateAPIView | 新增一条数据 |
ListCreateAPIView | 查询所有数据+新增一条数据 |
RetrieveAPIView | 查询一条数据 |
DestroyAPIView | 删除数据 |
UpdateAPIView | 修改数据 |
RetrieveUpdateAPIView | 查询一条数据+修改数据 |
RetrieveDestroyAPIView | 查询一条数据+删除数据 |
RetrieveUpdateDestroyAPIView | 查询一条数据+修改数据+删除数据 |
- 五个视图扩展类如下
名称 | 说明 | 方法 |
---|---|---|
ListModelMixin | 查询所有数据 | list |
RetrieveModelMixin | 查询单条数据 | retrieve |
CreateModelMixin | 新增一条数据 | create |
UpdateModelMixin | 修改一条数据 | update |
DestroyModelMixin | 删除一条数据 | destroy |
部分关系图
- 其它关系见下表
名称 | 关系 | 说明 |
---|---|---|
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请求
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏