【DRF框架之梅开二度】

DRF 框架

restful 规范

  • 定义
    • 软件的一种架构风格,通过HTTP协议进行数据交互。核心思想:将系统中的资源(网页,文本,数据等)表示为统一的资源标识符(URL)
    • 使用:POST,GET,PUT,DELETE等HTTP请求方法,对资源操作
  • 特点
    • 使用HTTP方法表示资源操作类型。GET 获取,POST创建,PUT更新,DELETE删除
    • 使用URL表示资源:URL尽可能多的反应资源的层次结构和名称
    • 使用状态码操作:2xx,4xx,5xx等
    • 使用JSON/XML作为数据传输格式。保证数据的可读性和可扩展性
    • 无状态:restful系统是无状态的,每个请求是独立的,不依赖之前的请求和会话
    • 缓存友好性:restful支持缓存,提高性能和减少服务资源负载

DRF 组件认证过程

1. 用户发送请求到 API端点(服务,服务器上的服务)
2. API检查请求头的Authorization字段,来确定请求是否经过认证
3. 如果请求未经过认证,则返回401,提示用户进行认证操作
4. 如果请求经过认证,则要求API检查请求的权限,确定用户是否具有执行该操作的权限
5. 如果用户执行该做操没有权限,则返回403,提示用户没有权限执行该操作
6. 如果用户具有该操作的权限,则执行API逻辑,并返回响应结果
7. 认证方式:基本认证,令牌认证,JSON WEB Token认证等

DRF 组件中的权限认证

- 视图级权限 ,视图中添加 permission_classes 属性指定权限
    from rest_framework.permissions import IsAuthenticated
    class MyView(APIView):
        permission_classes = (IsAuthenticated,)
            
- 路由级权限,路由中添加 permission_classes 属性指定权限
    from rest_framework.permissions import IsAuthenticated
    router = DefaultRouter()
    router.register(r'users', UserViewSet, base_name='user')
    router.route('list', permission_classes=(IsAuthenticated,))
- 自定义权限。
    from rest_framework.permissions import BasePermission
    class MyPermission(BasePermission):
        def has_permission(self, request, view):
            # 自定义权限逻辑
            return True
    
    class MyView(APIView):
        permission_classes = (MyPermission,)

DRF 组件中的节流实现方式

- 频率限制
    - 用户在一定时间可以发送的请求数量。如:限制用户每分钟只能发送10个请求。
    - 实现:通过cache模块,DRF提供 _throttled_cache 中间件,来实现频率限制
    - 代码如下:    
        from django.core.cache import cache
        from django.middleware.cache import ThrottledCache
        
        # 创建一个 ThrottledCache 实例
        throttled_cache = ThrottledCache(timeout=60, key_prefix='my_cache')
        
        # 将 ThrottledCache 实例添加到 DRF 的中间件列表中
        MIDDLEWARE = [
            xxxxx,
            xxxxx,
            'throttled_cache.middleware.ThrottledCacheMiddleware',
        ]


- 请求限制
    - 指某个IP在一定时间内发送的请求数量。如:限制43.10.10.22 ip 每小时只能发送1000个请求
    - 实现:使用django的request模块,DRF 提供 _throttled_request 中间件来限制
    - 代码:
        # 在视图中使用 ThrottledCache 中间件
        from rest_framework.response import JsonResponse 
        def my_view(request):
            # 检查请求是否被缓存
            if not throttled_cache.get_cache_key(request):
                return JsonResponse({'error': '请求太频繁,请稍后再试。'}, status=429)
        
            # 处理请求
            #...
        
            # 缓存请求
            throttled_cache.set_cache_key(request)
        
            # 返回响应
            return JsonResponse({'result': '请求处理成功。'})

什么是JWT?

  • 一般用于前后端分离项目。 用于做用户认证

  • jwt实现原理

    • 用户登陆成功后,返回一段字符串(token)
    • token 是由 三段组成
      • 第一段: 类型 和 算法 信息
      • 第二段: 用户信息 + 超时时间
      • 第三段: hs256加密 (拼接前两段信息)
    • 在使用 base64url 进行二次加密。(处理&和特殊字符)
    • 后端验证token
      • token 超时验证
      • token的合法性验证
  • jwt的优势

    • 服务端不保存token信息,只在客户浏览器保存。 后端只负责校验
    • 内部集成超时时间,后端可以根据时间校验token是否超时
    • 用户不可修改token,修改后token验证失败

Django 编写试图方式

  • 第一种:APIView
    • 自己编写CRUD视图,编写分页等
  • 第二种:ListAPIView,CreateAPIView等
    • 实现认证,分页,CRUD等
  • 第三种:GenericViewSet,ListModelMixin,CreateModelMixin等
    • 集成所有的功能,需要在路由指定方法
  • 第四种 viewsetes.ModelViewSet 实现上面所有功能

DRF 回顾

  • 装饰器
def wrapper(func):
    def inner(*args,**kwargs):
        ret = func(*args,**kwargs)
        return ret
    return inner

# 装饰器1
@wrapper
def index(f1):
    pass

# 装饰器2
index = wrapper(index)

  • django csrf_exempt 免认证

    from django.views.decorators.csrf import csrf_exempt
    from django.shortcuts import HttpResponse
    
    @csrf_exempt
    def index(request):
     return HttpResponse('...')
    
    # index = csrf_exempt(index)
    
    urlpatterns = [
     url(r'^index/$',index),
    ]
    
    urlpatterns = [
     url(r'^login/$',account.LoginView.as_view()),
    ]
    
    class APIView(View):
     @classmethod
     def as_view(cls, **initkwargs):
         view = super().as_view(**initkwargs)
         view.cls = cls
         view.initkwargs = initkwargs
    
         # Note: session based authentication is explicitly CSRF validated,
         # all other authentication is CSRF exempt.
         return csrf_exempt(view)
    
  • 面向对象中 基于 异常+继承 实现约束

    class BaseVersioning:
     def determine_version(self, request, *args, **kwargs):
         raise NotImplementedError("must be implemented")
         
    class URLPathVersioning(BaseVersioning):
    def determine_version(self, request, *args, **kwargs):
         version = kwargs.get(self.version_param, self.default_version)
         if version is None:
             version = self.default_version
    
         if not self.is_allowed_version(version):
             raise exceptions.NotFound(self.invalid_version_message)
         return version
    
  • 面向对象的封装

       class Foo(object):
       	def __init__(self,name,age):
       		self.name = name
       		self.age = age 
       		
       obj = Foo('汪洋',18)
    
    class APIView(View):
     def dispatch(self, request, *args, **kwargs):
    
         self.args = args
         self.kwargs = kwargs
         request = self.initialize_request(request, *args, **kwargs)
         self.request = request
       ...
         
    def initialize_request(self, request, *args, **kwargs):
         """
         Returns the initial request object.
         """
         parser_context = self.get_parser_context(request)
    
         return Request(
             request,
             parsers=self.get_parsers(),
             authenticators=self.get_authenticators(), # [MyAuthentication(),]
             negotiator=self.get_content_negotiator(),
             parser_context=parser_context
         )
    
  • 面向对象的继承

     class View(object):
        	pass
     
     class APIView(View):
         def dispatch(self):
             method = getattr(self,'get')
             method()
     
     class GenericAPIView(APIView):
         serilizer_class = None
         
         def get_seriliser_class(self):
             return self.serilizer_class
     
     class ListModelMixin(object):
         def get(self):
             ser_class = self.get_seriliser_class()
             print(ser_class)
     
     class ListAPIView(ListModelMixin,GenericAPIView):
         pass
     
     class UserInfoView(ListAPIView):
         pass
     
     
     view = UserInfoView()
     view.dispatch()
    
    class View(object):
    	pass
    
    class APIView(View):
     def dispatch(self):
         method = getattr(self,'get')
         method()
    
    class GenericAPIView(APIView):
     serilizer_class = None
     
     def get_seriliser_class(self):
         return self.serilizer_class
    
    class ListModelMixin(object):
     def get(self):
         ser_class = self.get_seriliser_class()
         print(ser_class)
    
    class ListAPIView(ListModelMixin,GenericAPIView):
     pass
    
    class UserInfoView(ListAPIView):
     serilizer_class = "汪洋"
    
    
    view = UserInfoView()
    view.dispatch()
    
    class View(object):
    	pass
    
    class APIView(View):
     def dispatch(self):
         method = getattr(self,'get')
         method()
    
    class GenericAPIView(APIView):
     serilizer_class = None
     
     def get_seriliser_class(self):
         return self.serilizer_class
    
    class ListModelMixin(object):
     def get(self):
         ser_class = self.get_seriliser_class()
         print(ser_class)
    
    class ListAPIView(ListModelMixin,GenericAPIView):
     pass
    
    class UserInfoView(ListAPIView):
     
     def get_seriliser_class(self):
         return "咩咩"
    
    view = UserInfoView()
    view.dispatch()
    
  • 反射

    class View(object):
    def dispatch(self, request, *args, **kwargs):
         # Try to dispatch to the right method; if a method doesn't exist,
         # defer to the error handler. Also defer to the error handler if the
         # request method isn't on the approved list.
         if request.method.lower() in self.http_method_names:
             handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
         else:
             handler = self.http_method_not_allowed
         return handler(request, *args, **kwargs)
    
  • 发送ajax请求

    $.ajax({
    	url:"地址",
    	type:"GET",
    	data:{},
    	success:function(e){
    		console.log(e)
    	}
    })
    
    
  • 浏览器具有 同源策略 跨域如何产生的? 导致 ajax请求+跨域 存在 无法获取数据

    • 简单请求,发送一次请求
    • 复杂请求,先做 options 请求预检,在发送真正的请求
    IP
    端口
    协议
    
  • 如何解决 跨域

    CORS 本质:设置响应头
    
  • 常见的HTTP请求方法

    Get,POST,PUT,OPTIONS,PATCH,DELETE ... 
    
  • HTTP 请求头。Content-Type 请求头

    - application/x-www-form-urlencoded
    	django 的 request.POST 和 request.body 中均有数据
    	
    - appliction/json
    	django 的 request.POST 没有值,request.body 有数据
    
  • django 的 fbv 和 cbv 都能遵循 restful 规范接口

  • django rest framework 框架 实现 restful api 开发

    - 免除 csrf 认证
    - 分页
    - 权限
    - 视图(APIView,ListApiView,ListModelMixin...) 类的继承
    - 序列化 serializer
    - 版本 Version
    - 节流
    - 解析器
    - 筛选器 
    - 认证
    - 渲染器 
    
  • 简述 drf 中的认证流程

  • 简述drf 中的节流实现原理, 匿名用户 和 非匿名用户 实现频率限制

  • GenericAPIView 视图类

    - 提供了一些规则
    	- serilizer_class = None
    	- lookup_field = 'pk'
    	- queryset = None
    	- filter_backends = 
    	- get_queryset(self)
    	- get_object(self)
    	- get_serializer_class(self):
    		return self.
    
  • jwt的优势

  • 序列化时,many=True 和 many = False 的区别

  • django 的 F 查询

  • django 的 获取空的queryset

    models.XXX.objects.all().none()
    
  • 应用 DRF 中的功能开发

    ***** 非常重要 
    	视图: 
    	序列化: 
    	解析器 request.data / request.query_params
    	渲染器:Response
    
    **** 
    	request 对象封装
    	版本处理
    	分页处理
    
    ***
    	认证
    	权限
    	节流
    	
    	
    - 基于 APIView 实现 呼啦圈 项目
    - 基于 GenericView,ListModelMixin 实现呼啦圈 项目
    
  • GenericAPIView视图类的作用?

        他提供了一些规则,例如:
        
        class GenericAPIView(APIView):
            serializer_class = None
            queryset = None
            lookup_field = 'pk'
            
            filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
            pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
            
            def get_queryset(self):
                return self.queryset
            
            def get_serializer_class(self):
                return self.serializer_class
            
        	def filter_queryset(self, queryset):
                for backend in list(self.filter_backends):
                    queryset = backend().filter_queryset(self.request, queryset, self)
                return queryset
            
            @property
            def paginator(self):
                if not hasattr(self, '_paginator'):
                    if self.pagination_class is None:
                        self._paginator = None
                    else:
                        self._paginator = self.pagination_class()
                return self._paginator
            
        他相当于提供了一些规则,建议子类中使用固定的方式获取数据,例如:
        class ArticleView(GenericAPIView):
            queryset = models.User.objects.all()
            
            def get(self,request,*args,**kwargs):
                query = self.get_queryset()
        
        我们可以自己继承GenericAPIView来实现具体操作,但是一般不会,因为更加麻烦。
        而GenericAPIView主要是提供给drf内部的 ListAPIView、Create....
        class ListModelMixin:
            def list(self, request, *args, **kwargs):
                queryset = self.filter_queryset(self.get_queryset())
        
                page = self.paginate_queryset(queryset)
                if page is not None:
                    serializer = self.get_serializer(page, many=True)
                    return self.get_paginated_response(serializer.data)
        
                serializer = self.get_serializer(queryset, many=True)
                return Response(serializer.data)
            
        class ListAPIView(mixins.ListModelMixin,GenericAPIView):
            def get(self, request, *args, **kwargs):
                return self.list(request, *args, **kwargs)
        
        class MyView(ListAPIView):
            queryset = xxxx 
            ser...
    
    总结:GenericAPIView主要为drf内部帮助我们提供增删改查的类LIstAPIView、CreateAPIView、UpdateAPIView、提供了执行流程和功能,我们在使用drf内置类做CURD时,就可以通过自定义 静态字段(类变量)或重写方法(get_queryset、get_serializer_class)来进行更高级的定制。
    
    
  • 序列化时many=True和many=False的区别?

    在 Django Rest Framework(DRF)中,序列化时 many=True 和 many=False 的区别在于它们指定了序列化的对象是单个实例还是一个集合。
      
      many=True 表示序列化的是一个集合(列表、可迭代对象等)。这意味着序列化器将处理多个对象,并返回一个包含多个序列化实例的数组或列表。
      many=False 表示序列化的是单个实例。序列化器将处理单个对象,并返回该单个序列化实例。
    
    以下是一些主要的区别:
    	返回格式:many=True 返回列表,many=False 返回单个对象。
    	数据处理:在序列化多个对象时,many=True 会逐个处理每个对象。
    	视图响应:根据 many 的设置,视图可能会返回不同的 HTTP 状态码和响应结构。
    	序列化逻辑:可能会有不同的逻辑来处理单个实例或集合。
    	通过设置 many 参数,DRF 可以灵活地处理单个对象和对象集合的序列化需求,以便与客户端进行有效的数据交互。
    
posted @ 2024-04-17 00:55  染指未来  阅读(11)  评论(0编辑  收藏  举报