一、路由Routers

在 Rest Framework 中提供了两个 router , 可以帮助我们快速的实现路的自动生成。

必须是继承 ModelViewSet 的视图类才能自动生成路由

SimpleRouter

使用方法:

urls.py

  1. # 第一步:导入routers模块
  2. from rest_framework import routers
  3. # 第二步:实例化得到对象
  4. router = routers.SimpleRouter()
  5. # 第三步:注册( register('前缀', viewset视图集, 路由的别名) )
  6. router.register('books', views.BooksViewset)
  7. # 第四步:生成路由加入到原路由中
  8. # 方式一:
  9. urlpatterns = [
  10. ...
  11. ]
  12. urlpatterns += router.urls
  13. # 方式二:
  14. urlpatterns = [
  15. ...
  16. url(r'^', include(router.urls))
  17. ]
  18. # 形成路由如下
  19. <URLPattern '^books/$' [name='books-list']>
  20. <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>

DefaultRouter

DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。

  1. # 前两条和SimpleRouter一样
  2. <URLPattern '^books/$' [name='books-list']>
  3. <URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']>
  4. # 效果也和前两条类似,
  5. # 如:http://127.0.0.1:8000/books.json
  6. <URLPattern '^books\.(?P<format>[a-z0-9]+)/?$' [name='books-list']>
  7. # http://127.0.0.1:8000/books/1.json
  8. <URLPattern '^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$' [name='books-detail']>
  9. # 多了个根路由http://127.0.0.1:8000/
  10. <URLPattern '^$' [name='api-root']>, <URLPattern '^\.(?P<format>[a-z0-9]+)/?$' [name='api-root']>

action的使用

action是为了给继承自 ModelViewSet 的视图类中自定义的函数也添加路由

例如下面这样:

  1. from rest_framework.viewsets import ModelViewSet
  2. from rest_framework.response import Response
  3. from app01.ser import BooksSerializers
  4. from app01.models import Books
  5. class BooksViewSet(ModelViewSet):
  6. queryset = Books.objects.all()
  7. serializer_class = BooksSerializers
  8. # 这种方法不会自动生成,需要用action配置
  9. def get_num(self, request, pk):
  10. book = self.get_queryset()[:int(pk)]
  11. ser = self.get_serializer(book, many=True)
  12. return Response(ser.data)

使用示例:

action是一个装饰器,放在被装饰的函数上方,

method:请求方式

detail:是否带pk ——>True 表示路径格式是xxx/<pk>/action方法名/——False 表示路径格式是xxx/action方法名/

  1. from rest_framework.viewsets import ModelViewSet
  2. from rest_framework.response import Response
  3. from rest_framework.decorators import action
  4. from app01.ser import BooksSerializers
  5. from app01.models import Books
  6. class BooksViewSet(ModelViewSet):
  7. queryset = Books.objects.all()
  8. serializer_class = BooksSerializers
  9. @action(methods=['GET', 'POST'], detail=True)
  10. def get_num(self, request, pk):
  11. book = self.get_queryset()[:int(pk)] # 获取前几条数据
  12. ser = self.get_serializer(book, many=True)
  13. return Response(ser.data)
  14. # 生成路由如下
  15. http://127.0.0.1:8000/books/2/get_num/
  16. <URLPattern '^books/(?P<pk>[^/.]+)/get_num/$' [name='books-get-num']>

二、认证

认证的写法

  1. 写一个认证类,继承 BaseAuthentication,重写 authenticate, 认证的逻辑写在里面,认证通过,返回两个值,一个值给Request对象的user, 认证失败,抛异常:APIException或者AuthenticationFailed
  2. 将认证类添加到需要认证视图类的authentication_classes = [认证类1]
  3. 全局使用,还是局部使用
  1. # 全局使用,在setting.py中配置
  2. REST_FRAMEWORK={
  3. "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
  4. }
  5. # 局部使用,在视图类上写
  6. authentication_classes=[MyAuthentication]
  7. # 局部禁用
  8. authentication_classes=[]

认证源码分析

1、APIView重写as_view方法使之没有csrf认证——>但还是正常执行 dispatch 方法,但是 dispatch方法被 APIView重写了——>dispatch 中执行了 self.initial 认证方法——>有认证,权限,频率

2、现在只是看认证源码self.perform_authentication(request)

3、但是self.perform_authentication(request)就一句话:request.user,那么就需要去 drf 的 Request 对象中找 user 属性(方法)

  1. @property
  2. def user(self):
  3. # 先去判断当前对象中有没有'_user'这个属性,一开始肯定是没有的,因为用户是没有登录的
  4. if not hasattr(self, '_user'):
  5. with wrap_attributeerrors():
  6. # 没有用户,认证出用户
  7. self._authenticate()
  8. # 有用户,直接返回用户
  9. return self._user

4、Request 类中的 user 方法,刚开始来,没有_user,走 self._authenticate()

5、核心,就是Request类中的 _authenticate(self)

  1. def _authenticate(self):
  2. # 遍历拿到一个认证器,进行认证
  3. # self.authenticators 配置的一堆认证类产生的认证类对象组成的 list
  4. # self.authenticators 就是在视图类中配置的:authentication_classes = [认证类1,认证类2] 的一个个认证类的对象:
  5. ————>self.authenticators ==》 [认证类1对象,认证类2对象]
  6. for authenticator in self.authenticators:
  7. try:
  8. # 认证器调用认证方法authenticate(认证类对象self,request对象)
  9. """
  10. def authenticate(self, request):
  11. return (self.force_user, self.force_token)
  12. """
  13. # 返回值:登录的用户与认证的信息组成的 tuple
  14. # 并且该方法被try包裹,就代表该方法会抛异常,抛异常就代表认证失败
  15. user_auth_tuple = authenticator.authenticate(self) # self是request对象
  16. except exceptions.APIException:
  17. self._not_authenticated()
  18. raise
  19. # 返回值的处理
  20. if user_auth_tuple is not None:
  21. self._authenticator = authenticator
  22. # 如果有返回值,就将 "登录用户" 与 "登录认证" 分别保存到 request.user / request.auth
  23. self.user, self.auth = user_auth_tuple
  24. return
  25. # 如果返回值user_auth_tuple为空,代表认证通过,但是没有 "登录用户" 与 "登录认证信息",代表游客
  26. self._not_authenticated()

认证组件的使用

1、写一个认证类,继承 BaseAuthentication,重写 authenticate

  1. # app01_auth.py
  2. from rest_framework.authentication import BaseAuthentication
  3. from rest_framework.exceptions import AuthenticationFailed
  4. from app01.models import UserToken
  5. class TokenAuthentication(BaseAuthentication):
  6. def authenticate(self, request):
  7. # 认证逻辑,如果认证通过,返回两个值
  8. # 如果认证失败,抛出AuthenticationFailed异常
  9. token = request.data.get('token')
  10. if token:
  11. user_token = UserToken.objects.filter(token=token).first()
  12. # 认证通过
  13. if user_token:
  14. return UserToken.user, token
  15. else:
  16. raise AuthenticationFailed('认证失败')
  17. else:
  18. raise AuthenticationFailed('请求地址中需要带token')

2、将认证类添加到需要认证视图类的authentication_classes = [认证类1]

  1. # views.py
  2. from rest_framework.viewsets import ModelViewSet
  3. from rest_framework.views import APIView
  4. from rest_framework.response import Response
  5. from app01.models import Books, UserInfo, UserToken
  6. from app01.ser import BooksSerializer
  7. from app01.app01_auth import TokenAuthentication
  8. import uuid
  9. # 查看Books需要经过认证才能查看
  10. class BooksView(ModelViewSet):
  11. authentication_classes = [TokenAuthentication]
  12. queryset = Books.objects.all()
  13. serializer_class = BooksSerializer
  14. # 登录视图,登录后获得token,后续用token认证
  15. class LoginView(APIView):
  16. def post(self, request):
  17. response_msg = {'status': 200, 'msg': ''}
  18. username = request.data.get('username')
  19. password = request.data.get('password')
  20. user_obj = UserInfo.objects.filter(username=username, password=password).first()
  21. if user_obj:
  22. # 登录成功生成一个随机字符串
  23. token = uuid.uuid4()
  24. # 存到UserToken表中,update_or_create有就更新,没有就新增
  25. UserToken.objects.update_or_create(defaults={'token': token}, user=user_obj)
  26. response_msg['msg'] = '登录成功'
  27. response_msg['token'] = token
  28. else:
  29. response_msg['msg'] = '账户或密码错误'
  30. response_msg['status'] = 204
  31. return Response(response_msg)

drf-路由和认证的更多相关文章

  1. drf路由与认证

    目录 一.路由 1 没有继承视图集的视图类 2 继承了视图集的视图类 3 继承自ModelViewSet的路由写法(自动生成) 二.认证 1 drf认证的源码分析 2 自定义认证类的使用 一.路由 三 ...

  2. drf路由分发、解析/渲染模块配置、使用admin、自动序列化配置

    目录 drf路由分发配置 解析模块配置 渲染模块配置 浏览器渲染打开 浏览器渲染关闭 结论 drf使用后台admin drf序列化模块 serializers.py: views.py:单查群查 测试 ...

  3. DRF内置认证组件之自定义认证系统

    自定义token认证 我们知道,在django项目中不管路由以及对应的视图类是如何写的,都会走到 dispatch 方法,进行路由分发, 在阅读 APIView类中的dispatch 方法的源码中,有 ...

  4. DRF框架之认证组件用法(第四天)

    1. 什么是drf 框架的认证组件: auth 就等于是jango中的Auth模块,Auth是自带session信息,但是 drf的认证组件可以自定义token携带过去,去判断用的 2.如何实现认证呢 ...

  5. drf框架中认证与权限工作原理及设置

    0909自我总结 drf框架中认证与权限工作原理及设置 一.概述 1.认证 工作原理 返回None => 游客 返回user,auth => 登录用户 抛出异常 => 非法用户 前台 ...

  6. 【DRF框架】认证组件

    DRF框架的认证组件 核心代码:       self.perform_authentication(request)  框架自带模块:    from rest_framework import a ...

  7. DRF的三大认证组件

    目录 DRF的三大认证组件 认证组件 工作原理 实现 权限组件 工作原理 实现 频率组件 工作原理 实现 三种组件的配置 DRF的三大认证组件 认证组件 工作原理 首先,认证组件是基于BaseAuth ...

  8. DRF 版本和认证

    Django Rest Framework 版本控制组件 DRF的版本 版本控制是做什么用的, 我们为什么要用 首先我们要知道我们的版本是干嘛用的呢~~大家都知道我们开发项目是有多个版本的~~ 当我们 ...

  9. Restful API学习Day4 - DRF版本控制和认证

    参考文档: Django REST framework基础:版本控制 Django REST framework基础:认证.权限.限制 为什么要有版本? 某些客户端 使用低版本只维护不开发新功能 v1 ...

  10. DRF 版本 及认证

    版本控制  -- # 初始化我们的版本   version, scheme = self.determine_version(request, *args, **kwargs)   request.v ...

随机推荐

  1. GCC参数详解-(转自:篱笆博客)

    gcc and g++分别是gnu的c & c++编译器 gcc/g++在执行编译工作的时候,总共需要4步 1.预处理,生成.i的文件[预处理器cpp] 2.将预处理后的文件不转换成汇编语言, ...

  2. flink-cdc读取postgres报异常,没有发布表

    异常信息 must be superuser to create FOR ALL TABLES publication 必须是超级用户才能为所有发布表创建 网上搜索了一天,都毫无头绪,后面搜索到了一个 ...

  3. 四:net core(.NET 6)使用Filter过滤器拦截webapi方法

    Filter的基本用法 代码在最下方 使用filter过滤器,来实现拦截接口信息.咱们先新建一个项目,在原有的webapi上面,选择添加项目,添加一个类库项目: 我起个名字,就叫 Wsk.Core.F ...

  4. ngx_lua模块

    ngx_lua模块的原理: 1.每个worker(工作进程)创建一个Lua VM,worker内所有协程共享VM:2.将Nginx I/O原语封装后注入 Lua VM,允许Lua代码直接访问:3.每个 ...

  5. GO语言基础---值传递与引用传递

    package main import ( "fmt" ) /* 值传递 函数的[形式参数]是对[实际参数]的值拷贝 所有对地址中内容的修改都与外界的实际参数无关 所有基本数据类型 ...

  6. Camera Lens Coating

    Camera Lens Coating Coating Progress 转换镜头,根据要求进行OEM和设计. 光学元件:望远镜.显微镜.相机和数码相机镜头.放大镜头和远摄镜头.定心镜头.投影镜头.投 ...

  7. 在 CUDA C/C++ kernel中使用内存

    在 CUDA C/C++ kernel中使用内存 如何在主机和设备之间高效地移动数据.本文将讨论如何有效地从内核中访问设备存储器,特别是 全局内存 . 在 CUDA 设备上有几种内存,每种内存的作用域 ...

  8. 从C到C++过渡的3个原因

    从C到C++过渡的3个原因 3 reasons to transition from C to C++ 几十年来,嵌入式软件工程师们一直在争论他们是否应该使用C或C++.根据2019年嵌入式市场调查, ...

  9. SQL Parameter参数的用法

    SqlParameter 类 表示 SqlCommand 的参数,也可以是它到 DataSet 列的映射. 无法继承此类. 命名空间:  System.Data.SqlClient 程序集:  Sys ...

  10. 深入 Go 中各个高性能 JSON 解析库

    转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com/archives/535 其实本来我是没打算去看 JSON 库的性能问题的,但是最近我对 ...