drf之路由
自动生成路由
drf 由于继承ViewSetMixin类,路由写法变了,原生django+drf,以后的路由写法,可能会有如下情况(三种情况)
-path('books/', views.BookView.as_view()
-path('books/', views.BookView.as_view({'get': 'list', 'post': 'create'}))
-自动生成
drf提供了两个路由类,继承ModelViewSet后,路由可以自动生成,使用步骤如下:
# 第一步:导入路由类
# 第二步,实例化得到对象(两个类,一般使用SimpleRouter)
# 第三步:注册:router.register('books', views.BookView, 'books')
# 第四步:在urlpatterns中注册,两种方式
-urlpatterns += router.urls
-include:path('/api/v1/', include(router.urls)) 方式多一些
代码如下:
urls.py
# 第一步:导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter
# 第二步,实例化得到对象
router = SimpleRouter() # 后面这个生成路由少的用的多
# router = DefaultRouter()
# 生成多个路由,到底多了几个:
# 1 Api Root :访问根(/),可以看到有那些地址,比如book的,比如publish的
# 2 会给别的路由自动起别名,后期一般都用SimpleRouter
'SimpleRouter()与DefaultRouter()的区别'
# DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图(就是访问根),返回一个包含所有列表视图的超链接响应数据
# 第三步:注册
# 第一个参数是路径,不要带 /
# 第二个参数是视图类
# 第三个参数是别名,一般跟路径相同
router.register('books', views.BookView, 'books') # 路径和视图类建立关系 有几个视图类就要写几次
# 第四步:在urlpatterns中注册,两种方式
# 方式一:
urlpatterns += router.urls
print(router.urls) # [<URLPattern '^books/$' [name='books-list']>, <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>]
第四步方式二:
# 第一步:导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter
# 第二步,实例化得到对象
router = SimpleRouter()
# 第三步:注册
router.register('books', views.BookView, 'books')
# 第四步:在urlpatterns中注册
'在上方导入模块'
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls)),
]
'我们可以发现,这里的第二种注册方式我们可以进行一定程度的自定义,最终的路由就是:自定义部分+自动生成部分,因此将来使用第二种方式的情况居多'
底层实现:自动生成路由
-本质是自动做映射,能够自动成的前提是,视图类中要用到5个方法中的某个或多个,并且用上了ViewSetMixin类(它的as_view方法就是做映射)
get--->list
get---->retrieve
put---->update
post---->create
delete---->destory
-因此ModelViewSet,ReadOnlyModelViewSet可以自动生成路由
-9个试图子类+配合ViewSetMixin 才可以自动生成
-GenericAPIView+5个试图扩展类+配合ViewSetMixin才能自动生成。同时GenericAPIView和ViewSetMixin可以替换成GenericViewSet
路由总结:
# 0 视图类没有继承了ViewSetMixin,路由写法跟之前一样
path('books/', views.BookView.as_view())
# 1 只要视图类继承了ViewSetMixin,路由写法必须写成映射的方式
path('books/', views.BookView.as_view({'get': 'list'})),
#2 只要视图类继承了ModelViewSet,还可以这么写
#1 导入
from rest_framework.routers import SimpleRouter
#2 实例化
router = SimpleRouter()
#3 注册路径
router.register('books', views.BookView, 'books')
#4 加入到路由中
urlpatterns += router.urls
# 5 list,create,retrieve,destroy,update--->自动映射--》SimpleRouter
# 3 假设视图类中有个login,如何做对应?
from rest_framework.decorators import action
class BookView(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# list,create,retrieve,destroy,update--->自动映射--》SimpleRouter
# 手动映射
#methods=None, 请求方式
# detail=None, 只能写True或False,如果写了false就是不带pk的路径,如果写了True路径带pk
# False的情况: http://127.0.0.1:8080/api/v1/books/login/
# True 的情况: http://127.0.0.1:8080/api/v1/books/8/login/
# url_path='login' 路径,会在之前的路径上,拼这个路径,如果不写默认以函数名拼接
# - http://127.0.0.1:8080/api/v1/books/login/
# url_name=None :别名,用做反向解析
@action(methods=['POST'],detail=False,)
def login(self,request):
return Response('login')
# 4 总结:以后只要继承ViewSetMixin,就可以使用SimpleRouter方式写路由
#1 导入
from rest_framework.routers import SimpleRouter,DefaultRouter
#2 实例化 :SimpleRouter,DefaultRouter
router = SimpleRouter()
或:认为他们一样即可---》DefaultRouter多一条路径
router = DefaultRouter()
#3 注册路径
router.register('books', views.BookView, 'books')
#4 加入到路由中:
# 方式一:(用这个)
urlpatterns += router.urls
# 方式二:
urlpatterns = [
path('', include(router.urls)),
]
# 5 list,create,retrieve,destroy,update--->自动映射--》SimpleRouter
# 6 视图类中自己的方法,再做映射--action装饰器
@action(methods=['POST'],detail=False,)
def login(self,request):
return Response('login')
action 装饰器
当我们想对视图类中的get、post等方法,自定义方法名称或同意名称的方法有多个请求方式的时候,我们需要使用action装饰器,这样才能使用自动生成路由。
def action(methods=None, detail=None, url_path=None, url_name=None, **kwargs):
通过action装饰器的源码我们发现他内部主要有四个参数,作用如下:
- method:声明该action对应的请求方式,以列表的方式存入,可以写多个请求方式
- detail:默认是False(只能传True和False),控制生成的路由是什么样子,如果是True则会加上PK,必须是数字。
-False,不带id的路径:send/send_sms/
-True,带id的路径:send/2/send_sms/
- ulr_path: 控制生成的路由后面的路径名称是什么,如果不写默认以被装饰的方法名为路径名称
- url_name: 别名 用于反向解析
使用步骤:
- 1 写在视图类方法上
from rest_framework.decorators import action
class SendView(ViewSet):
@action(methods=['POST'], detail=False)
def send_sms(self, request):
ps:以后看到的drf路由写法,都是自动生成,一般不在urlpatterns 加入路由了
补充
- 1 不同请求方式可以使用不同序列化类
- 2 不同action使用不同序列化类
class SendView(GenericViewSet):
queryset = None
serializer_class = '序列化类'
'这里我们通过重写get_serializer方法来根据请求方式选择不同的序列化类'
def get_serializer(self, *args, **kwargs):
if self.action=='lqz':
return '某个序列化类'
else:
return '另一个序列化列'
@action(methods=['GET'], detail=True)
def send_sms(self, request,pk):
print(pk)
# 手机号,从哪去,假设get请求,携带了参数
phone = request.query_params.get('phone')
print('发送成功,%s' % phone)
return Response({'code': 100, 'msg': '发送成功'})
@action(methods=['GET'], detail=True)
def lqz(self,request): # get
# 序列化类
pass
@action(methods=['GET'], detail=True)
def login(self,request): # get
# 序列化类
pass
认证组件
# 认证---》登录认证
-登录进系统后,以后再访问接口,需要携带登录信息,如果没携带,不允许方法---》这个控制就是认证
-cookie(客户端浏览器上)和session(后端存储的键值对)
# 写个登录
# 后续访问某些接口,携带登录信息--->session--->后端校验(认证组件)
# 认证组件步骤
1 写个认证类,继承BaseAuthentication
2 在类中重写 authenticate,在方法中完成认证,如果通过,返回两个值,如果失败,抛异常
def authenticate(self, request):
# 完成对用户的校验
# 当次请求request
token = request.query_params.get('token')
# 表中校验
user_token = UserToken.objects.filter(token=token).first()
# 当前登录用户
if user_token:
user = user_token.user
# 校验过后,返回两个值
return user, user_token
else:
raise AuthenticationFailed("token不合法")
3 使用认证类:放在需要登录后才能访问的视图类上
class BookView(ReadOnlyModelViewSet): # 5个接口必须写到正确的token才能访问
authentication_classes = [LoginAuth]
标签:视图,action,books,SimpleRouter,组件,router,路由,drf
From: https://www.cnblogs.com/wolongnp/p/17931470.html