DRF 路由组件
DRF 路由组件
路由的配置上篇我们提到了一点自动配置,对于继承了视图集ViewSet就可以自动生成路由,当然了也可以选择手动版自己配,可以使用action装饰器来指定方法等操作,屁话不多说如下:
REST framework提供了两个router
- SimpleRouter
- DefaultRouter
路由组件使用,如果视图类继承了ViewSetMixin及其子类,那么路由写法可以改变,而且视图类中的方法也可以自定制,不一定是get,post,可以随意命名
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin
from rest_framework.response import Response
class TestView(ViewSetMixin,APIView):
def login(self,requets):
return Response('test-login')
# 路由
path('test/',views.TestView.as_view({'get': 'login'}))
注意
继承的时候,如果继承了ModelViewSet就相当于继承了ViewSetMixin的子类了,不需要继承ViewSetMixin了,不然会报错
class BookView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
path('books/', views.BookView.as_view({'get':'list'})),
路由是如何映射的?
1、ViewSetMixin写在前面
2、先走ViewSetMixin的as_view
if not actions:
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`")
4、如果actions不传就报错,也就是as_view()内不写字典就报错
5、view闭包函数
def view(request, *args, **kwargs):
self = cls(**initkwargs)
····
for method, action in actions.items():
'''method:get action:login'''
# 把login方法的内存地址给了handler
handler = getattr(self, action)
# 通过反射,设置给get---》对应login---》get请求执行get方法,现在get方法变成了login方法
setattr(self, method, handler)
return self.dispatch(request, *args, **kwargs)# 跟之前一样了
继承ModelViewSet,路由写法
ModelViewSet继承了五个扩展类+GenericViewSet,提供了相应的接口方法增删改查
from rest_framework.viewsets import ModelViewSet
class BookView(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookSerializer
自己配路由的映射
path('books/', views.BookView.as_view({'get':'list','post':'create'})),
path('books/<int:pk>', views.BookView.as_view({'get':'retrieve','put':'update','delete':'destroy'}))
自动生成路由
from rest_framework.routers import SimpleRouter
from app01 import views
router = SimpleRouter()
router.register('books', views.BookView, 'books')
urlpatterns = [
path('api/v1/', include(router.urls)),
]
'''
或者不写path('api/v1/', include(router.urls)),写下面的
urlpatterns += router.urls
'''
action装饰器
只要是继承ViewSetMixin视图类或其子类,都可以加action装饰器
导入:rest_framework.decorators.action
参数:
- methods:请求方法,列表的形式写
- detail:是否带id,True不带id,False带id
- url_path:地址,地址如果不写,默认已方法名为地址
- url_name:起别名
继承APIView+ViewSetMixin使用装饰器
from rest_framework.decorators import action
class TestView(ViewSetMixin,APIView):
@action(methods=['GET','POST'],detail=False)
def login(self,requets):
return Response('test-login')
from rest_framework.routers import SimpleRouter
from app01 import views
router1 = SimpleRouter()
router1.register('test',views.TestView,'test')
urlpatterns = [
path('aip/v2/', include(router1.urls)),
]
'''
http://127.0.0.1:8000/aip/v2/test/login/
'''
注意:
如果这样写detail=True
,路由就成了http://127.0.0.1:8000/aip/v2/test/1/login/
,数字的部分一般为pk
最后都是路由前缀拼接一个方法名
路由router形成URL的方式
1) SimpleRouter
2)DefaultRouter
DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据
总结
路由的写法有三种:
-
手动配置:
path('books/<int:pk>', views.BookDetailView.as_view())
-
继承ViewSetMixin,使用action属性:
views.PublishView.as_view({'get':'list','post':'create'}))
-
使用SimpleRouter或DefaultRouter自动生成(两种方式):
router = SimpleRouter() router.register('books', views.PublishView, 'books') urlpatterns = [ path('api/v1/', include(router.urls)), ] # 或者 urlpatterns = [ urlpatterns+=router.urls ]
-
DefaultRouter比SimpleRouter多一层根路径