一.上节回顾
1 web应用开发模式
2 API接口
3 接口测试工具
4 restful规范( 重点)
5 djangorestframework: drf, django的app, 快速的写出符合restful规范的API接口
6 drf的执行流程( APIView源码: request对象, 认证, 权限, 频率, 捕获全局异常, 响应对象)
7 序列化器( 序列化, 反序列化, 数据校验) : ( 重点** ** * )
- Serializer
- 字段自己写, 字段类型, 字段属性
- read_only write_only
- 序列化: 实例化得到对象: instance, many, data( many= True : __call__)
- 对象. data: 字典
- 反序列化
- 重写: create, update
- 反序列化的校验通过, 修改会触发update, 新增会触发create
- 反序列化的数据校验( 三种方式) : 源码部分
- 扩展: source, SerializerMethodField
- ModelSerializer
- 内部类
- class Meta :
model= model. Book
fileds= '__all__'
exclude= [ ]
read_only_field= [ ]
extra_kwargs= { }
depth= 1
- Serializer用法, 重写字段, 指定字段类型, 字段参数
- 局部钩子, 全局钩子
- 不需要重写create和update( 经常看到重写)
8 请求和响应( 次重点)
- Request
- request. data
- request. query_param
- 读源码: 重写了__getattr__
- Response
- 客户端请求数据看到的样子( json, 浏览器)
- 局部配置: 在视图函数中render_classes= [ ]
- 全局配置: settings中配置
- drf默认有一套配置文件
9 视图( 重点)
- 2 个视图基类: APIView和GenericAPIView
- GenericAPIView:
- queryset= None
- serializer_class= None
- get_queryset: 获取要序列化的数据( 可以重写, 自己定制规则)
- get_serializer: 获取序列化类( 可以重写, 自己定制返回哪个序列化类)
- get_object: 返回单个对象, 通过pk查的( 可以重写, 返回谁, 单个对象就是谁)
- 5 个视图扩展类( rest_framework. mixin)
CreateModelMixin: create方法创建一条
DestroyModelMixin: destroy方法删除一条
ListModelMixin: list 方法获取所有
RetrieveModelMixin: retrieve获取一条
UpdateModelMixin: update修改一条
- 9 个视图扩展类
CreateAPIView: 继承CreateModelMixix, GenericAPIView, 有post方法, 新增数据
DestroyAPIView: 继承DestroyModelMixin, GenericAPIView, 有delete方法, 删除数据
ListAPIView: 继承ListModelMixin, GenericAPIView, 有get方法获取所有
UpdateAPIView: 继承UpdateModelMixin, GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin, GenericAPIView,有get方法,获取一条
ListCreateAPIView:继承ListModelMixin, CreateModelMixin, GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin, DestroyModelMixin, GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin, UpdateModelMixin, GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin, GenericAPIView,有get获取一条,put,patch修改,delete删除
- 视图集
ViewSetMixin: 重写了as_view( 一旦继承了它, 路由就变了)
ViewSet: 继承ViewSetMixin和APIView
GenericViewSet: 继承ViewSetMixin, generic. GenericAPIView
ModelViewSet:继承mixins. CreateModelMixin, mixins. RetrieveModelMixin, mixins. UpdateModelMixin, mixins. DestroyModelMixin, mixins. ListModelMixin, GenericViewSet
ReadOnlyModelViewSet:继承mixins. RetrieveModelMixin, mixins. ListModelMixin, GenericViewSet
10 路由( 重点)
- 三种方式配置路由
- 自动生成路由
- 导入SimpleRouter, 实例化得到对象
- router. register( 'book' , 视图类( 必须继承ViewSetMixin及它的子类) )
- 两种方式注册进路由中
- urlpatterns += router. urls
- urlpatterns= [
. . .
url( r'^' , include( router. urls) )
]
- 半自动
url( r'books/' , BookView. as_view( { 'get' : 'list' } ) )
- 原始的
- action装饰器( 也会自动生成路由)
- 127.0 .0 .1 / books/ get_new_5 detail= False
- 127.0 .0 .1 / books/ pk/ get_new_5 detail= True
- @action( method= [ 'put' ] , detail= True )
def get_new_5 ( self, request, pk) :
return Response( { 'msg' : '获取5条数据成功' } )
二.今日内容
1 drf认证功能介绍
0 认证, 频率, 权限
1 用户是否登录到系统中
2 后期基本上会用JWT的认证
3 自定制的认证
2 认证功能源码分析
1 APIView- - - > dispatch- - - > self. initial( request, * args, ** kwargs) - - > self. perform_authentication( request) - - - > Request. user- - - > self. _authenticate( self) : Request类的方法- - - > self. authenticators: Request类的属性- - - > 在Request对象实例化的时候传入的- - - > Request在什么时候实例化的?dispatch的时候- - - > APIView: self. get_authenticators( ) - - > return [ auth( ) for auth in self. authentication_classes] - - - > 如果在自己定义的视图类中写了authentication_classes= [ 类1 , 类2 ] - - - > Request的self. authenticators就编程了我们配置的一个个类的对象
2 self. _authenticate( self) : Request类的方法
def _authenticate ( self) :
for authenticator in self. authenticators:
try :
user_auth_tuple= authenticator. authenticate( self)
except exceptions. APIException:
self. _not_authenticated( )
raise
if user_auth_tuple is not None :
self. _authenticator= authenticator
self. user, self. auth= user_auth_tuple
return
3 只要在视图类中配置authentication_classes= [ MyAuthen. LoginAuth, ] 就会执行上面的方法, 执行认证
3.自定义认证类(重点)
1 使用
- 在app下建一个任意名字的py文件
- 定义一个类, 继承BaseAuthentication
from rest_framework. authentication import BaseAuthentication
class LoginAuth ( BaseAuthentication) :
def authenticate ( self, request) :
token= request. GET. get( 'token' )
res= models. UserInfo. objects. filter ( token= token) . first( )
if res:
return 元组
else :
raise AuthenticationFailed( '您没有登录' )
- 重写authenticate方法
- 局部使用和全局使用
- 局部: 在视图类中配置( 只要配置了, 就要登录以后才能访问, 没配置, 不用登录就能访问)
authentication_classes= [ myauthen. LoginAuth, ]
- 全局
REST_FRAMEWORK= {
"DEFAULT_AUTHENTICATION_CLASSES" : [ "app01.myauthen.LoginAuth" , ]
}
- 注意:
1 . 认证类, 认证通过可以返回一个元祖, 有两个值, 第一个值会给request. user, 第二个值会给request. auth
2 . 认证类可以配置多个, 按照从前向后的顺序执行, 如果前面有返回值, 认证就不再继续往下走了
4.认证功能局部使用和全局使用
1 全局使用( 所有接口, 都需要登录才能访问)
- 在配置文件中
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES" : [ "app01.myauthen.LoginAuth" , ]
}
2 局部使用
- 在想局部使用的视图类上写上下面这条
authentication_classes = [ myauthen. LoginAuth, ]
3 局部禁用
- 在想禁用的视图类上
authentication_classes = [ ]
代码演示
urlpatterns = [
path( 'admin/' , admin. site. urls) ,
path( 'login/' , views. LoginView. as_view( ) ) ,
path( 'books/' , views. BookView. as_view( ) ) ,
path( 'publish/' , views. PublishView. as_view( ) ) ,
]
class User ( models. Model) :
username= models. CharField( max_length= 32 )
password= models. CharField( max_length= 32 )
class UserToken ( models. Model) :
user= models. OneToOneField( to= 'User' , on_delete= models. CASCADE)
token= models. CharField( max_length= 64 )
from app01 import models
from rest_framework. exceptions import AuthenticationFailed
from rest_framework. authentication import BaseAuthentication
class LoginAuth ( BaseAuthentication) :
def authenticate ( self, request) :
token = request. GET. get( 'token' )
res = models. UserToken. objects. filter ( token= token) . first( )
if res:
return ( res. user, token)
else :
raise AuthenticationFailed( '您没有登录' )
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES" : [ "app01.MyAuthen.LoginAuth" , ] ,
}
from app01 import MyAuthen
from rest_framework. views import APIView
from rest_framework. request import Request
from rest_framework. response import Response
class BookView ( APIView) :
authentication_classes = [ myauthen. LoginAuth, ]
def get ( self, request) :
print ( request. user)
print ( request. auth)
return Response( '获取了所有图书' )
class PublishView ( APIView) :
def get ( self, request) :
return Response( '获取了出版社' )
from app01 import models
import uuid
class LoginView ( APIView) :
authentication_classes = [ ]
def post ( self, request) :
res = { 'code' : 100 , 'msg' : '登录成功' }
username = request. data. get( 'username' )
password = request. data. get( 'password' )
user = models. User. objects. filter ( username= username, password= password) . first( )
if user:
token = uuid. uuid4( )
models. UserToken. objects. update_or_create( defaults= { 'token' : token} , user= user)
res[ 'token' ] = token
return Response( res)
else :
res[ 'code' ] = 101
res[ 'msg' ] = '用户名或密码错误'
return Response( res)
5 自定义权限功能(重点)
1 登录成功以后, 超级用户可以干某些事, 普通用户不能干- - > 超级用户可以查看某些接口,普通用户不能查看
2 使用
- 写一个类继承BasePermission,重写has_permission
class SuperPermission ( BasePermission) :
def has_permission ( self, request, view) :
if request. user. user_type == 1 :
return True
else :
return False
3 局部使用和全局使用
- 在想局部使用的视图类上
permission_classes = [ myauthen. SuperPermission]
- 全局使用
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES" : [ "app01.myauthen.SuperPermission" , ]
}
- 局部禁用
permission_classes = [ ]
6 权限功能局部使用和全局使用
1 使用方式
- 在想局部使用的视图类上
permission_classes = [ myauthen. SuperPermission]
- 全局使用
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES" : [ "app01.myauthen.SuperPermission" , ]
}
- 局部禁用
permission_classes = [ ]
代码演示
urlpatterns = [
path( 'admin/' , admin. site. urls) ,
path( 'login/' , views. LoginView. as_view( ) ) ,
path( 'books/' , views. BookView. as_view( ) ) ,
path( 'publish/' , views. PublishView. as_view( ) ) ,
]
class User ( models. Model) :
username= models. CharField( max_length= 32 )
password= models. CharField( max_length= 32 )
user_type= models. IntegerField( choices= ( ( 1 , '超级用户' ) , ( 2 , '普通用户' ) , ( 3 , '沙雕用户' ) ) , default= 1 )
class UserToken ( models. Model) :
user= models. OneToOneField( to= 'User' , on_delete= models. CASCADE)
token= models. CharField( max_length= 64 )
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES" : [ "app01.myauthen.LoginAuth" , ] ,
"DEFAULT_PERMISSION_CLASSES" : [ "app01.myauthen.SuperPermission" , ]
}
from app01 import models
from rest_framework. exceptions import AuthenticationFailed
from rest_framework. authentication import BaseAuthentication
class LoginAuth ( BaseAuthentication) :
def authenticate ( self, request) :
token = request. GET. get( 'token' )
res = models. UserToken. objects. filter ( token= token) . first( )
if res:
return ( res. user, token)
else :
raise AuthenticationFailed( '您没有登录' )
from rest_framework. permissions import BasePermission
class SuperPermission ( BasePermission) :
def has_permission ( self, request, view) :
user= request. user
if user. user_type == 1 :
return True
else :
return False
from app01 import myauthen
from app01 import models
from rest_framework. response import Response
from rest_framework. views import APIView
class BookView ( APIView) :
authentication_classes = [ myauthen. LoginAuth, ]
permission_classes = [ myauthen. SuperPermission, ]
def get ( self, request) :
print ( request. user)
print ( request. auth)
return Response( '获取了所有图书' )
class PublishView ( APIView) :
def get ( self, request) :
return Response( '获取了所有出版社' )
import uuid
class LoginView ( APIView) :
authentication_classes = [ myauthen. LoginAuth, ]
def post ( self, request) :
res= { 'code' : 100 , 'msg' : '登录成功' }
username= request. data. get( 'username' )
password= request. data. get( 'password' )
user= models. User. objects. filter ( username= username, password= password) . first( )
if user:
token= uuid. uuid4( )
models. UserToken. objects. update_or_create( defaults= { 'token' : token} , user= user)
res[ 'token' ] = token
return Response( res)
else :
res[ 'code' ] = 101
res[ 'msg' ] = '用户名或密码错误'
return Response( res)
7 内置的权限和认证类
from rest_framework. exceptions import AuthenticationFailed
from rest_framework. permissions import BasePermission
扩展
1 select_related的使用
articleList= models. Article. objects. select_related( "category" ) . all ( )
for article_obj in articleList:
print ( article_obj. category. title)
2 mysql的悲观锁和乐观锁
3 drf内部内置了一些认证类,分别干了什么事
三.作业
0 整理出认证和权限的使用,局部配置和全局配置
1 写一个图书的5 个接口出版社的5 个接口和登录接口
- 用户必须登录才能访问图书的5 个接口
- 必须超级用户登录后才能访问出版社5 个接口
2 阅读认证源码,整理出流程
2 ( 拓展) 阅读权限源码,整理出流程(错误信息的中文显示)