drf之路由、认证组件

发布时间 2023-12-27 21:25:23作者: jntmwl

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]