DRF总结-入门规范、序列化组件、视图组件、请求与响应、路由组件和action装饰器、认证权限频率、过滤排序分页、接口文档、接口文档、权限:acl,rbac

DRF总结

1 drf入门规范
2 序列化组件
3 视图组件
4 请求与响应
5 路由组件和action装饰器
6 认证权限频率
7 过滤排序分页
8 接口文档
9 jwt认证
10 权限:acl,rbac

# 1 drf 入门规范
# 2 序列化组件---(最重要)
# 3 视图组件----(重要)
# 4 请求与响应
# 5 路由组件
# 6 认证,权限,频率---重要
# 7 过滤,排序,分页,全局异常
# 8 接口文档
# 9 jwt认证
# 10 权限:acl,rbac

1 drf入门规范

# 1 前后端开发模式
	-混合(前后端不分离
    -分离:后端只负责写接口
    	-5个接口
    	
# 2 API 接口
	-Web API接口和一般的url链接还是有区别的,Web API接口简单概括有下面四大特点
		url:长得像返回数据的url链接
			https://api.map.baidu.com/place/v2/search
		请求方式:get、post、put、patch、delete
			采用get方式请求上方接口
		请求参数:json或xml格式的key-value类型数据
			ak:6E823f587c95f0148c19993539b99295
			region:上海
			query:肯德基
			output:json
		响应结果:json或xml格式的数据
			上方请求参数的output参数值决定了响应数据的格式
		数据
'''
# xml格式
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295®ion=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=xml
#json格式
https://api.map.baidu.com/place/v2/search?ak=6E823f587c95f0148c19993539b99295®ion=%E4%B8%8A%E6%B5%B7&query=%E8%82%AF%E5%BE%B7%E5%9F%BA&output=json
{
    "status":0,
  	"message":"ok",
    "results":[
        {
            "name":"肯德基(罗餐厅)",
            "location":{
                "lat":31.415354,
                "lng":121.357339
            },
            "address":"月罗路2380号",
            "province":"上海市",
            "city":"上海市",
            "area":"宝山区",
            "street_id":"339ed41ae1d6dc320a5cb37c",
            "telephone":"(021)56761006",
            "detail":1,
            "uid":"339ed41ae1d6dc320a5cb37c"
        }
      	...
		]
}
'''

	-后期写的那些接口,前后端交互的媒介
    	-请求地址
        -请求方式
        -请求参数:地址,请求体
        -返回数据
    -写了接口给谁用? 前端(web,app),提供给第三方调用
    
    
# 3 接口测试工具--postman
	-发送http请求工具
    -get请求可以在请求体中携带数据
    -get请求和post请求有什么区别?
    -请求编码格式:
    	urlencoded:key=value&key=value---->后端django--》request.POST
        form-data: 数据和文件混到一起-----》后端django--》request.FILES,request.POST
        json: {name:lin,age:19}-----》后端django--》request.body---->装饰器
    -collections创建,保存导出
    
# 4 接口规范:restful规范
	-1 数据的安全保障-》url链接一般都采用https协议进行传输--》它比http安全
	-2 接口特征表现--》url中带api标识
    	-https://api.baidu.com/books/
        -https://www.baidu.com/api/books/
            
    -3 多数据版本共存--》url中带版本信息
    	https://api.baidu.com/v1/books
		https://www.baidu.com/api/v2/books
            
    -4 数据即是资源,均使用名词(可复数)-->前后台交互,交互的数据称之为资源
    	-数据即资源,前后端交互的数据称之为资源,url尽量使用名字
    	-https://127.0.0.1/api/v1/books/  -->表示对图书操作:增加,删除,查询,修改,都用这一个地址
        -https://127.0.0.1/api/v1/get_all_books/ # 不符合restful规范
        -https://127.0.0.1/api/v1/delete_books/# 不符合restful规范
   -5 资源操作由请求方式决定
		-get 请求获取数据(获取所有,获取单条)
    	-post 新增数据
        -put 修改数据
        -delete 删除数据
        https://api.baidu.com/books - get请求:获取所有书
        https://api.baidu.com/books/1 - get请求:获取主键为1的书
        https://api.baidu.com/books - post请求:新增一本书书
        https://api.baidu.com/books/1 - put请求:整体修改主键为1的书
        https://api.baidu.com/books/1 - delete请求:删除主键为1的书
            
            
  -6  请求地址中带过滤条件---》只针对于搜索所有接口
	
    
  -7 响应状态码(两层)
	-http响应状态码: 1xx,2xx,3xx,4xx,5xx:https://www.sohu.com/a/278045231_120014184
    	-404403405
        -301302
        -1xx表示请求正在处理---》前端一般看不到
        -2xx 表示请求处理成功--》经常看到
        	-201200有什么区别
        -3xx:重定向
        -4xx:客户端错误
        -5xx:服务端出错
        
    -成功都返回200,而在响应体中带 状态码--->code不同公司就不一样
    	{
            "code": 101,
            "msg": "用户名或密码错误"
        }
        
    -补充一:mysql 错误操作都会有个 数字(10060)  文字解释
    -补充二:
    -https://open.weibo.com/wiki/Error_code
    
 -8 响应中带错误信息
	{
            "code": 101,
            "msg": "用户名或密码错误"
        }
    
 -9 不同操作,返回格式符合如下标准
	GET /collection:返回资源对象的列表(数组)
    	# [{name:西游记,price:19},{name:三国,price:19}]
    GET /collection/resource:返回单个资源对象 
    	# {name:三国,price:19}
    POST /collection:返回新生成的资源对象
    	# {name:三国,price:19}
    PUT /collection/resource:返回完整的资源对象
    	# {name:三国演绎,price:19}
    DELETE /collection/resource:返回一个空文档
    	#   
        
    ---》大家都这么做
    {
        code:100
        msg:查询成功
        restult:[{name:西游记,price:19},{name:三国,price:19}]
    }
    
    
 -10 响应中带链接

    
# 5 序列化和反序列化
	-序列化:把我们识别的数据转成对方识别的数据:字典,列表---》转成json格式字符串的过程
    -反序列化:别人提供给我们数据转成我们识别的格式---》json格式字符串---》字典,对象。。
    
    
    
# 6 drf:django框架上的一个app,方便我们快速编写符合restful规范的接口
	-快速写了5个接口
    '''
	   1 安装模块
    	1 django 是2版本,用不了drf最新(适当降版本),他会卸载django---》装最新4.x
        2 djagno 3.1.12 可以使用drf最新	
        	-django:3.1.12
            -drf:3.14.0
                
	    2 在app中注册
	        INSTALLED_APPS = [
	            'rest_framework',  # 一定不要忘了加  ,
	        ]
	    	
	    3 写路由
	    from rest_framework.routers import DefaultRouter
	    router = DefaultRouter()
	    router.register('books', BookView, 'books')
	    
	    urlpatterns += router.urls
	    
	    4 写视图类
	    from rest_framework.viewsets import ModelViewSet
	    from .serializer import BookSerializer
	    class BookView(ModelViewSet):
	        queryset = Book.objects.all()
	        serializer_class = BookSerializer
	        
	    5 写序列化类
	    class BookSerializer(serializers.ModelSerializer):
	    class Meta:
	        model = Book
	        fields = "__all__"
	'''
    
# 7 cbv源码分析
	-路由   视图类.as_view()(request)   执行视图类中跟请求方式同名的方法
    '''
		@classonlymethod
		def as_view(cls, **initkwargs):
		    # 闭包函数
		    def view(request, *args, **kwargs):
		        self = cls(**initkwargs) # 类实例化得到对象:BookView的对象
		        # 调用对象的绑定方法 dispath---》去BookView中找dispatch--》找不到去父类---》View中的dispatch
		        return self.dispatch(request, *args, **kwargs) # 对象的方法
		    return view
		    
		# 执行:BookView.as_view()(request)---》本质是执行 View中as_view内部的view方法,传入了reuqest----》在执行View的dispatch方法,传入了request
		
		# 看 :View.dispatch---》源码
		    def dispatch(self, request, *args, **kwargs):
		        if request.method.lower() in self.http_method_names: # 判断请求方式是否在那个固定的列表中[get, post...]--->
		            # 反射:通过字符串 动态的  操作对象的属性或方法
		            # 假设是get请求---》去BookView中取出 get方法赋值给handler
		            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
		        else:
		            handler = self.http_method_not_allowed
		        # 执行handler加括号,传入了request
		        # 本质是执行 get(request)
		        return handler(request, *args, **kwargs)
		    
		    
		#### 总结:
			请求来了---》执行 BookView.as_view()(request)---》内部执行了---》View的as_view的内部的view闭包函数---》闭包函数调用了 self.dispatch---->是BookView的,于是去了View的----》通过反射获取跟请求方式同名的方法---》然后执行,把request传入
	'''
    
    
# 8 APIView的执行流程
	-执行视图类中跟请求方式同名的方法
    -去除了csrf认证
    -包装了新的request
    -执行了三大认证
    -处理了全局异常
    
    -视图类的对象  self.request

2 序列化组件

# 1 序列化组件作用
	1 可以序列化--》qs对象,单个对象
    2 反序列化--》前端传入的json格式数据---》保存到数据库
    3 反序列化的校验:字段自己,局部钩子,全局钩子
    
# 2 快速使用 
	-写个类,继承Serializer
    -在类中写字段
    -在视图类中:实例化得到序列化类的对象:多条,和单条
    -序列化:序列化类的对象.data  retrun Response(ser.data)
# 3 常用字段类
	-跟models中之前学过的有对应关系
    -ListField   DictField  --->序列化和反序列化都会用
    
    
# 4 字段参数
	-限制反序列化校验字段自己规则的
    
    -read_only  write_only:控制字段只做序列化或反序列化的,如果不写就是
    
    
# 5 使用序列化类做反序列化
	-新增
        ser=BookSerializer(data=request.data)
        ser.is_valid(raise_exception=True)--->只要校验不通过,直接抛异常
        ser.save()  # 继承Serializer,需要在序列化类中重写create方法,完成新增
    	序列化类中重写create方法
        def create(self, validated_data):
            # validated_data 前端传入,校验过后的数据
            # 新增一个对象
            return  新增的对象  # 后续再视图类中只要调用ser.data,这里必须返回
    
    -修改
    ser=BookSerializer(instance=要修改的对象,data=request.data)
    ser.is_valid(raise_exception=True)--->只要校验不通过,直接抛异常
    ser.save()  # 继承Serializer,需要在序列化类中重写update方法,完成修改
    序列化类中重写update
    def update(self, instance, validated_data):
        # instance 要修改的对象,哪里来的?BookSerializer(instance=要修改的对象的id,data=request.data)
        # validated_data:校验过后数据
        res=Book.objects.filter(pk=instance).update(**validated_data)
        return res   # 返回的res最后干啥了?只要在  视图类中 调用ser.data,他会根据这个返回值做序列化
    
    
# 6 反序列化校验
	-字段自己
    -局部钩子--》序列化类中写  validate_字段名  传参数
    -全局钩子---》序列化类中写  validate       传参数,字典
    	-登录接口
    
    
# 7 定制返回格式
	-source:1 改名  2 跨表查  3 拿表模型中的方法
		# 高级用法source
	    # 用法1:
	    xxx = serializers.CharField(source='name')  # name映射成xxx
	
	    # 用法2:
	    # 自动对应成出版社的名字,可以通过  跨表查询
	    publish = serializers.CharField(source='publish.name')
	
	    # 用法3:
	    # 要在models.py文件中写对相应的方法名用property装饰器装饰
	    yyy = serializers.CharField(source='get_name')

    -SerializerMethodField:在序列化类中写
    	-publish=serializers.SerializerMethodField(read_only)
        -配合一个 get_username(self,obj)的方法,返回什么,这个字段就是什么
    
    -在表模型中写:方法
    	publish=serializers.DictField()
    
    -只能做序列化用了,反序列化得单独用---》需要使用read_only和write_only控制
    
# 8 ModelSerializer使用
	class Meta:
        model=表名
        fields=[需要序列化或反序列化的字段,表中没有也要写]
        extra_kwargs={} # 传入字段参数
    重写字段
    
    大部分情况下不需要写create和update了
    
    局部,全局钩子跟之前一模一样

3 视图组件

# 1 两个视图基类
	APIVIew
    	-类属性
            renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
            parser_classes = api_settings.DEFAULT_PARSER_CLASSES
            authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
            throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
            permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
    GenericAPIView:要使用序列化类,数据库打交道,就可以继承它
    	-queryset = None
    	-serializer_class = None
        -lookup_field = 'pk'
        -filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
        -pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
        
        -get_queryset(self) #获取所有要序列化的数据,在里面拿到qs对象后要 .all()
        -get_object  # 获取单个对象
        -get_serializer()--->内部调用了get_serializer_class--》最终返回序列化类的对象,传入要传的参数---》instance ,data  many
        
        -filter_queryset---》给ListModelMixin用了--》把配置的filter_backends 依次执行完成过滤
# 5个视图扩展类 =不是视图类,需要搭配GenericAPIView
	ListModelMixin,
    CreateModelMixin,
    UpdateModelMixin,
    DestroyModelMixin,
    RetrieveModelMixin
    
    一个视图类中写四个接口--》必须借助于ViewSetMixin
class BookView(ViewSetMixin,GenericAPIView,ListModelMixin,CreateModelMixin,RetrieveModelMixin,DestroyModelMixin):
    queryset = None
    serializer_class = None
    
    
    
# 6 9个视图子类

# 7 视图集
	-ModelViewSet:重写方法实现你想要的功能
    -ReadOnlyModelViewSet
    -ViewSetMixin:路由写法变了
    -ViewSet:ViewSetMixin+APIView
    -GenericViewSet:ViewSetMixin+GenericAPIView
	

4 请求与响应

# 请求:
	-请求源码:request对象
    	-request.data
        -request.query_params
        -跟之前一样
        -request._request
        -__getattr__
    -请求能解析编码格式:parser_classes
    	-局部使用
        -全局使用
        
"""
class BookView(APIView):
    '''
    # 方式二:编码格式全局使用,以及浏览器和postman的响应编码格式
    REST_FRAMEWORK = {
        # 全局配置编码格式
        'DEFAULT_PARSER_CLASSES': [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser'
        ],
        # 全局配置响应编码格式
        'DEFAULT_RENDERER_CLASSES': [
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.BrowsableAPIRenderer',
        ],
    }
    '''
    # 类属性 -----> parser是解析的意思

    # 方式一:局部使用:视图类上配置编码格式,优先用局部的
    # 如果以后这个视图类的所有方法,只能接收json格式的数据,别的接收不了,
    # 只需要在 parser_classes 中传入 JSONParser
    # parser_classes = [JSONParser]

    # 如果在setting.py中配置了全局,这里没有使用局部配置,就用全局的
    # 或者在布局重新配置
    parser_classes = [JSONParser, FormParser, MultiPartParser]

    # 响应编码格式
    renderer_classes = [JSONRenderer, BrowsableAPIRenderer]

    def get(self, request):
        # self 就是BookView的对象
        print(self.request is request)  # True
        print(self.headers)  # {'Allow': 'GET, POST, HEAD, OPTIONS', 'Vary': 'Accept'}
        '''
        def __init__(self, data=None, status=None, template_name=None, headers=None,
                 exception=False, content_type=None):
        data=None             # 字符串,列表,字典------> 放在了响应体中------>它是__init__()的第一个参数
        status=None           # 这是http响应状态码,默认是200,不能使用status=100,这表示请求正在处理
        template_name=None    # 模板名字默认是:rest_framework/api.html  可以定制自己返回的页面
        headers=None          # http响应头,后期我们往响应头中放数据
        exception=False
        content_type=None     # 响应编码格式
        '''
        res = Response(data={}, status=200, headers={'xxx': 'yyyy'})
        print(res.data)
        print(res.has_header('xxx'))  # True
        return res

    def post(self, request):
        # 请求体中带数据 ------> http请求有请求地址:请求头、请求体
        # 带在请求体中的数据,有编码格式:3种 ------> 无论是哪种,携带的数据都是从 request.data 中获取
        # 假设这个接口,只允许携带 json 格式,其他格式都报错,怎么做呢?
        # 需要配置类属性
        print(request.data)
        return Response('新增')
"""
        
        
# 响应
	-响应Response  源码
    	-data:响应体的内容,序列化后的数据给了他
        -headers:响应头    django原生响应头  响应对象['xx']=xxx
        -status:响应状态码
	-响应编码格式--》浏览器,postman,看到的样子
    	-局部和全局配置
            
# 写了个视图类  获取所有接口
class BookView(ViewSetMixin,GenericAPIView,ListModelMixin):
    queryset = None
    serializer_class = None
    def list(self,request,*args,**kwargs):
        res=super().list(request,*args,**kwargs)
        res.data  # {code:100,msg:成功,data:[{},{}]}
        return Response({code:100,msg:成功,data:res.data})
# 相应格式
"""
# 响应有编码格式:默认支持json和text/html(浏览器)

# 修改只支持json
### 局部使用
class BookView(APIView):
   	renderer_classes = [BrowsableAPIRenderer]
### 全局使用
REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ],
}

##局部禁用---》全局已经配置了---》局部想用浏览器的样子
class BookView(APIView):
   	renderer_classes = [BrowsableAPIRenderer]
    
    
    
# 如果不配置---》有默认
	-解析:三种编码都能解析
    -响应:浏览器访问看到浏览器的样子,postman访问,看到json格式
"""

5 路由组件和action装饰器

# 1 只要继承ViewSetMixin及其子类,路由写法就变了
	-方式一:映射方式
    	视图类.as_view({'get':'lqz'})
    -方式二:自动生成
    	-SimpleRouter  DefaultRouter
"""

# 大前提:必须是继承ViewSetMixin+APIView及其子类才能自动生成
####使用步骤
# urls.py中
#### 1 导入路由类
from rest_framework.routers import SimpleRouter, DefaultRouter

#### 2 类实例化得到对象
router = SimpleRouter()

#### 3 自动生成路由,调用对象的某个方法,完成跟视图类的对应关系,映射路由
router.register('publish', PublishView, 'publish')
# router.register('books', BookView, 'books') #  后期可以注册更多
router.register('user',UserView,'user')

##### 4 把自动生成的路由,加到总路由中
urlpatterns = urlpatterns + router.urls  # 两个列表直接相加

### 第四步可以这样写
	path('api/v1/', include(router.urls)),   # http://127.0.0.1:8008/api/v1/user/register/--->post
	
"""      
        
# 2 action装饰器:methods  detail
"""
# 作用:为视图类中的方法做路径的映射
	-这些方法排除5个 :create,list,destroy。。。
    
# 使用方式
    @action(methods=['POST'],detail=False)
    def register(self, request):
        return Response('register')
        
# 自动生成:
	http://127.0.0.1:8008/user/register/---->post--->就会执行register
	
# action参数
	-methods请求方式,可以写多个
    -detail:路径中是否带id号  
    	http://127.0.0.1:8008/user/register/    # detail=False
        http://127.0.0.1:8008/user/4/register/  # detail=True
        
"""  

6 认证权限频率

# 认证的使用
	1 写个类,继承BaseAuthentication
    2 重写autenticate
    3 取出用户传入的 token  ---》通过token能知道是谁
    4 认证通过取出用户,认证失败,抛出异常
    5 return 查到的对象,token---》后续再request.user中就是当时返回的第一个值
	6 视图类中配置
    7 全局配置
    
# 权限类
	1 写个类,继承BasePermission
    2 has_permission
    3 判断用户的权限  
    	acl 权限,取出当前用户所有权限,判断当次请求是否在权限中
        rbac,根据当前用户取出所有角色,通过角色取出所有权限,去个重,判断是否在权限中
    4 有权限返回True,没有返回False
	5 视图类中配置
    6 全局配置
    
    
 # 频率类
	1 写个类,继承SimpleRatethrottle
    2 重写get_cache_key 返回值 唯一的  ip,userid
    3 类属性  scope='字符串'  
    4 配置文件配置 
    'DEFAULT_THROTTLE_RATES': {
        '字符串': '3/m',
    },
	5 视图类中配置
    6 全局配置
	
    
    
 # 权限---》认证---》频率


# 为什么我们写了 权限类,配置行,它就会执行权限控制?
	-APIView 的dispatch中执行了3大认证---def dispatch(self, request, *args, **kwargs):
         self.initial(request, *args, **kwargs) # 三大认证
        
        
    - self.initial   需要从根上
      def initial(self, request, *args, **kwargs):
        self.perform_authentication(request)
        self.check_permissions(request) # 权限类的执行位置
        self.check_throttles(request)
        
    -self.check_permissions(request)
      def check_permissions(self, request):
        for permission in self.get_permissions(): # 你配置在视图类上一个个权限类的对象列表 [权限对象1,权限对象2]
            if not permission.has_permission(request, self): # self,是视图类的对象,因为在APIView中
                self.permission_denied(
                    request,
                    message=getattr(permission, 'message', None),
                    code=getattr(permission, 'code', None)
                )
                
    - def get_permissions(self):
        return [permission() for permission in self.permission_classes]
    
    
    
    
# 认证类源码---》难
-APIView 的dispatch中执行了3大认证---def dispatch(self, request, *args, **kwargs):
         self.initial(request, *args, **kwargs) # 三大认证
        
        
    - self.initial   需要从根上
      def initial(self, request, *args, **kwargs):
        self.perform_authentication(request)# 认证类的执行位置
        self.check_permissions(request) 
        self.check_throttles(request)
        
   - def perform_authentication(self, request):
        request.user
   -去Request类中找user---》方法包装成了数据属性
        @property
        def user(self):
            if not hasattr(self, '_user'):
                with wrap_attributeerrors():
                    self._authenticate()
            return self._user
        
    -去Request类中找self._authenticate()
        def _authenticate(self):
            for authenticator in self.authenticators: # 配置在视图类上一个个认证类的对象列表
                try:
                    # 调用认证类对象的authenticate方法,传入 self,是request对象
                    user_auth_tuple = authenticator.authenticate(self) # 当前登录用户,token
                except exceptions.APIException:
                    self._not_authenticated()
                    raise

                if user_auth_tuple is not None:
                    self._authenticator = authenticator
                    #self就是request对象,后续 request.user就是认证类返回的第一个参数
                    self.user, self.auth = user_auth_tuple  # 解压赋值
                    return

            self._not_authenticated()
            
     -认证类可以配置多个,但是如果有一个返回了,后续的就不走了
    
    -self.authenticators 是request对象的属性,是在Request实例化的时候传入的,它什么时候实例化的,包装新的Reqeust时传入的---》APIView的dispatch--

7 过滤排序分页

在这里插入代码片

8 接口文档

在这里插入代码片

9 jwt认证

在这里插入代码片

10 权限:acl,rbac

在这里插入代码片

你可能感兴趣的:(django,python01,jwt,django,token,Authentication,RateThrottle,permission,action)