文章目录
- 一、路由组件
- REST framework提供了两个router
- action装饰器
- 二、认证组件
一、路由组件
对于
视图集ViewSetMixin
,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。
REST framework提供了两个router
- SimpleRouter
- DefaultRouter
也就是通过路由组件帮助我们自动生成路由,
它会根据URL及请求匹配对应的视图方法,而这些方法则是来自视图集
,如果我们需要自定义方法来处理请求的话,后续可以搭配action装饰器实现。
SimpleRouter为每个URL添加一个斜杠后缀,可以在初始化的时候提供trailing_slash参数,并设置为False
创建router对象,并注册视图集
'导入'from rest_framework.routers import SimpleRouter,DefaultRouter'导入的模块不是继承就是实例化'router = SimpleRouter() 或者DefaultRouter() # 创建对象'''DefaultRouter会生成一个根路径/的配置项DefaultRouter生成的每个配置项后都可以跟上.json,直接返回json数据还可以显示注册过的路由以及美化的页面SimpleRouter和DefaultRouter用法一致,功能几乎一样''''注册路径,可以注册多个'router.register('publish',views.PublishView) # 注册路由,并选择视图函数'注册:第一个参数是路径,第二个参数为视图类,第三个参数起别名用得少所有这里没用'urlpatterns = []'把生成的路由添加到urlpatterns路由列表中,有两种方式:'# 将生成的路由加入到Django需要调用的路由列表内'方式一:直接添加+='urlpatterns += router.urls'方式二:直接添加到urlpatterns里面使用include'from django.urls import path,includeurlpatterns = [path('',include(router.urls))]
def register(self, prefix, viewset, basename=None):
注册参数说明:
- prefix:路由的前缀
- viewset:视图集(内部必须继承了ViewSetMixin类)
- basename:路由的别名
上序代码会生成如下路由:
path('publish/',views.PublishView.as_view()),path('publish/<int:pk>',views.PublishView.as_view()),''''^publish/$' [name='publish-list^publish/(?P<pk>[^/.]+)/$' [name='publish-detail']'''
每个路由对应的接口功能
publish/:get请求的话则会执行视图集里面的list方法publish/:post请求的话则会执行视图集里面的create方法publish/<int:pk>/:get请求执行视图集里面的retrieve方法publish/<int:pk>/:put请求执行视图集里面的update方法publish/<int:pk>/:delete请求执行视图集里面的destroy方法
实际展示
视图类
from rest_framework.viewsets import ModelViewSet'必须是继承了ViewSetMixin类的视图类才能使用这种自动生成路由的方法'class PublishView(ModelViewSet):queryset = models.Publish.objects.all()serializer_class = PublishSerializer
路由
from rest_framework.routers import SimpleRouterrouter = SimpleRouter()router.register('publish',views.PublishView)urlpatterns = []urlpatterns += router.urls
此时上面代码就可以自动生成路由了,完成了增、删、改、查(一条或多条数据)的接口了,但是不包括在视图集里面自定义的方法。
如果要给我们自定义的方法也加上路由,那么则需要使用action装饰器来声明。
SimpleRouter生成URL的方式
DefaultRouter生成URL的方式
action装饰器
在视图集中,如果想要让Router自动帮助我们为自定义的方法生成路由信息,需要使用
rest_framework.decorators.action
装饰器。
使用action装饰器的方法名会作为路由的后缀,例如:
/publish/使用action装饰器的方法名/
并且action装饰器会接收两个参数:
- methods:声明该action对应的请求方式,列表传递:
['get','post']
表示该路由get请求与post请求。 - detail:声明该action的路由是否与单一资源
(就是单条数据)
对应,如果需要的话设置True。
/publish/<int:pk>/使用action装饰器的方法名/True:表示路径格式是:/publish/pk/action方法名/False:表示路径格式是:/publish/action方法名/
- url_path:控制生成的/使用action装饰器的方法名/后面的路径是什么,如果不写默认以方法名
- url_name:别名,用于反向解析
实际案例
视图类
from rest_framework.viewsets import ModelViewSetfrom rest_framework.response import Responsefrom rest_framework.decorators import actionclass PublishView(ModelViewSet):queryset = models.Publish.objects.all()serializer_class = PublishSerializer@action(methods=['post'], detail=False)def login(self,request):return Response({'message':'登录成功'})@action(methods=['get'],detail=True)def test(self,request,pk):return Response({'message':'测试成功'})
效果展示
此时可以从浏览器上看到自动生成的路由
api/v1/ ^publish/$ [name='publish-list']api/v1/ ^publish/login/$ [name='publish-login']api/v1/ ^publish/(?P<pk>[^/.]+)/$ [name='publish-detail']api/v1/ ^publish/(?P<pk>[^/.]+)/test/$ [name='publish-test']
它使用的是
正则来匹配
,中间使用了有名分组,以关键字:pk=xx
的形式传给视图。
二、认证组件
在DRF中,我们要进行登录认证的话需要使用DRF内部的认证组件,为什么不用auth组件?因为DRF重新封装了request方法,而当我们使用原来
reqeust.use
r时,则会调用_authenticate
方法,然后在调用我们编写的认证类里面的authenticate
方法进行认证。
开启认证有两种方法:
- 局部开启
- 全局开启
全局开启方式:在settings.py文件里面进行DRF配置
REST_FRAMEWORK={"DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.LoginAuth"]# value值是我们认证组件类在当前项目的路径}
局部开启:在视图类里面指定认证类
'导入登录认证类'from .auth import LoginAuthauthentication_classes = [test.LoginAuth, ]# 认证可以有多个,在调用_authenticate方法时会将列表里面类实例成对象,然后执行对象里面的authenticate方法。# 执行顺序从前至后,如果某个对象返回了正确结果则后面对象不会执行。'如果全局认证了但是又不想让某一个不认证,需要再视图类里面写入authenticate_classes = []清空即可'
登录认证类
from rest_framework.authentication import BaseAuthenticationfrom . import modelsfrom rest_framework.exceptions import AuthenticationFailed'''通过认证类完成,使用步骤1 写一个认证类,继承BaseAuthentication2 重写authenticate方法,在内部做认证3 如果认证通过,返回2个值4 认证不通过抛AuthenticationFailed异常5 只要返回了两个值,在后续的request.user 就是当前登录用户'''class LoginAuth(BaseAuthentication):def authenticate(self, request): 重写authenticate方法,做内部认证# 完成对用户的校验# 当次请求的requesttoken = request.query_params.get('token') 获取tokenuser_token = models.UserToken.objects.filter(token=token).first()if user_token:user = user_token.user # 如果通过认证返回两个值,不通过则抛异常return user,user_token'质押返回了两个值,在后续的request.user就是当前登录用户'else:raise AuthenticationFailed('token不存在!')