drf 知识点总结

day85

内容回顾和补充

  1. restful规范

  2. drf组件认证的实现过程?

  3. drf组件中权限的实现过程?

  4. drf组件中节流的实现方式?

    - 实现原理
    - 具体流程
  5. 什么是jwt?优势?

    一般在前后端分离时,用于做用户认证(登录)使用的技术。
    jwt的实现原理:
    - 用户登录成功之后,会给前端返回一段token。
    - token是由.分割的三段组成。
    - 第一段:类型和算法信心
    - 第二段:用户信息+超时时间
    - 第三段:hs256(前两段拼接)加密 + base64url
    - 以后前端再次发来信息时
    - 超时验证
    - token合法性校验
    优势:
    - token只在前端保存,后端只负责校验。
    - 内部集成了超时时间,后端可以根据时间进行校验是否超时。
    - 由于内部存在hash256加密,所以用户不可以修改token,只要一修改就认证失败。

     

今日概要

  • 呼啦圈作业

  • paramiko模块

  • 练习题:django + paramiko实现远程对某些服务器执行命令+上传文件

 

 

今日详细

1.写视图的方法

  • 第一种:原始APIView

    url(r'^login/$',account.LoginView.as_view()),
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework_jwt.settings import api_settings
    from rest_framework.throttling import AnonRateThrottle
    from api import models


    class LoginView(APIView):
      authentication_classes = []
      def post(self,request,*args,**kwargs):
          # 1.根据用户名和密码检测用户是否可以登录
          user = models.UserInfo.objects.filter(username=request.data.get('username'),password=request.data.get('password')).first()
          if not user:
              return Response({'code':10001,'error':'用户名或密码错误'})

          # 2. 根据user对象生成payload(中间值的数据)
          jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
          payload = jwt_payload_handler(user)

          # 3. 构造前面数据,base64加密;中间数据base64加密;前两段拼接然后做hs256加密(加盐),再做base64加密。生成token
          jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
          token = jwt_encode_handler(payload)
          return Response({'code': 10000, 'data': token})
  • 第二种:ListApiView等

    url(r'^article/$',article.ArticleView.as_view()),
    url(r'^article/(?P<pk>\d+)/$',article.ArticleDetailView.as_view()),
    from rest_framework.throttling import AnonRateThrottle
    from rest_framework.response import Response
    from rest_framework.generics import ListAPIView,RetrieveAPIView
    from api import models
    from api.serializer.article import ArticleSerializer,ArticleDetailSerializer

    class ArticleView(ListAPIView):
      authentication_classes = []
      # throttle_classes = [AnonRateThrottle,]

      queryset = models.Article.objects.all()
      serializer_class = ArticleSerializer

    class ArticleDetailView(RetrieveAPIView):
      authentication_classes = []
      queryset = models.Article.objects.all()
      serializer_class = ArticleDetailSerializer
  • 第三种:

    url(r'^article/$',article.ArticleView.as_view({"get":'list','post':'create'})),
      url(r'^article/(?P<pk>\d+)/$',article.ArticleView.as_view({'get':'retrieve','put':'update','patch':'partial_update','delete':'destroy'}))
    from rest_framework.viewsets import GenericViewSet
    from rest_framework.mixins import ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin
    from api.serializer.article import ArticleSerializer,ArticleDetailSerializer

    class ArticleView(GenericViewSet,ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin):
      authentication_classes = []
      throttle_classes = [AnonRateThrottle,]

      queryset = models.Article.objects.all()
      serializer_class = None

      def get_serializer_class(self):
          pk = self.kwargs.get('pk')
          if pk:
              return ArticleDetailSerializer
          return ArticleSerializer

     

drf 相关知识点梳理

  1. 装饰器


    def outer(func):
       def inner(*args,**kwargs):
           return func(*args,**kwargs)
       return inner

    @outer
    def index(a1):
       pass

    index()
    def outer(func):
       def inner(*args,**kwargs):
           return func(*args,**kwargs)
       return inner

    def index(a1):
       pass

    index = outer(index)

    index()
  2. django中可以免除csrftoken认证

    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)
  3. 面向对象中基于继承+异常处理来做的约束

    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
  4. 面向对象封装

    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
          )
  5. 面向对象继承

    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()
  6. 反射

    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)
  7. 发送ajax请求


    $.ajax({
    url:'地址',
    type:'GET',
    data:{...},
    success:function(arg){
    console.log(arg);
    }
    })
  8. 浏览器具有 "同源策略的限制",导致 发送ajax请求 + 跨域 存在无法获取数据。

    • 简单请求,发送一次请求。

    • 复杂请求,先options请求做预检,然后再发送真正请求


    <!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="UTF-8">
       <title>Title</title>
    </head>
    <body>
       <h1>常鑫的网站</h1>
       <p>
           <input type="button" value="点我" onclick="sendMsg()">
       </p>
       <p>
           <input type="button" value="点他" onclick="sendRemoteMsg()">
       </p>

     
       <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
       <script>
           function sendMsg() {
               $.ajax({
                   url:'/msg/',
                   type:'GET',
                   success:function (arg) {
                       console.log(arg);
                  }
              })
          }
           function sendRemoteMsg() {
               $.ajax({
                   url:'http://127.0.0.1:8002/json/',
                   type:'GET',
                   success:function (arg) {
                       console.log(arg);
                  }
              })

          }
       </script>
    </body>
    </html>
  9. 如何解决ajax+跨域?

    CORS,跨站资源共享,本质:设置响应头。
  10. 常见的Http请求方法

    get
    post
    put
    patch
    delete
    options
  11. http请求中Content-type请起头

    情况一:
      content-type:x-www-form-urlencode
      name=alex&age=19&xx=10

    request.POST和request.body中均有值。

    情况二:
    content-type:application/json
      {"name":"ALex","Age":19}
       
      request.POST没值
      request.body有值。
  12. django中F查询

  13. django中获取空Queryset

    models.User.object.all().none()
  14. 基于django的fbv和cbv都能实现遵循restful规范的接口


    def user(request):
       if request.metho == 'GET':
           pass
       
       
    class UserView(View):
       def get()...
       
       def post...
  15. 基于django rest framework框架实现restful api的开发。

    - 免除csrf认证
    - 视图(APIView、ListAPIView、ListModelMinx)
    - 版本
    - 认证
    - 权限
    - 节流
    - 解析器
    - 筛选器
    - 分页
    - 序列化
    - 渲染器
  16. 简述drf中认证流程?

  17. 简述drf中节流的实现原理以及过程?匿名用户/非匿名用户 如何实现频率限制?

  18. 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)来进行更高级的定制。
  19. jwt以及其优势。

  20. 序列化时many=True和many=False的区别?

  21. 应用DRF中的功能进行项目开发

    *****
    解析器:request.query_parmas/request.data
    视图
    序列化
    渲染器:Response

    ****
    request对象封装
    版本处理
    分页处理
    ***
    认证
    权限
    节流
    • 基于APIView实现呼啦圈

    • 继承ListAPIView+ GenericViewSet,ListModelMixin实现呼啦圈

 

 

2.paramiko

用于帮助开发者通过代码远程连接服务器,并对服务器进行操作。

pip3 install paramiko 
  • 远程执行命令【用户名和密码】

    import paramiko

    # 创建SSH对象
    ssh = paramiko.SSHClient()

    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    # 连接服务器
    ssh.connect(hostname='192.168.16.85', port=22, username='root', password='123456')

    # 执行命令
    stdin, stdout, stderr = ssh.exec_command('df')
    # 获取命令结果
    result = stdout.read()
    # 关闭连接
    ssh.close()

    print(result.decode('utf-8'))
  • 远程执行命令【公钥和私钥】(公钥必须提前上传到服务器)

    import paramiko

    private_key = paramiko.RSAKey.from_private_key_file(r'C:/Users/Administrator/.ssh/id_rsa')

    # 创建SSH对象
    ssh = paramiko.SSHClient()
    # 允许连接不在know_hosts文件中的主机
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    # 连接服务器
    ssh.connect(hostname='192.168.16.85', port=22, username='root', pkey=private_key)

    # 执行命令
    stdin, stdout, stderr = ssh.exec_command('df')
    # 获取命令结果
    result = stdout.read()

    # 关闭连接
    ssh.close()

    print(result)
  • 远程上传和下载文件【用户名和密码】

    import paramiko

    transport = paramiko.Transport(('192.168.16.85', 22))
    transport.connect(username='root', password='123456')
    sftp = paramiko.SFTPClient.from_transport(transport)


    # 将location.py 上传至服务器 /tmp/test.py
    # sftp.put('wy.txt', '/data/wy.txt')
    sftp.get('/data/wy.txt', 'xx.txt')

    transport.close()
  • 远程上传和下载文件【公钥和私钥】

    import paramiko

    private_key = paramiko.RSAKey.from_private_key_file(r'C:/Users/Administrator/.ssh/id_rsa')

    transport = paramiko.Transport(('192.168.16.85', 22))
    transport.connect(username='root', pkey=private_key)

    sftp = paramiko.SFTPClient.from_transport(transport)
    # 将location.py 上传至服务器 /tmp/test.py
    # sftp.put('/tmp/location.py', '/tmp/test.py')

    # 将remove_path 下载到本地 local_path
    # sftp.get('remove_path', 'local_path')

    transport.close()

     

补充:通过私钥字符串也可以连接远程服务器。

key = """-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----"""


import paramiko
from io import StringIO

private_key = paramiko.RSAKey(file_obj=StringIO(key))

# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.16.85', port=22, username='root', pkey=private_key)

# 执行命令
stdin, stdout, stderr = ssh.exec_command('df')
# 获取命令结果
result = stdout.read()

# 关闭连接
ssh.close()

print(result)

 

 

 

 

 

公司员工基于xshell连接服务器

  • 用户名和密码

  • 公钥和私钥(rsa)

    • 生成公钥和私钥

      ssh-keygen.exe -m pem

      在当前用户家目录会生成: .ssh/id_rsa.pub   .ssh/id_rsa
    • 把公钥放到服务器

      ssh-copy-id -i ~.ssh/id_rsa.pub root@192.168.16.85 
    • 以后再连接服务器时,不需要在输入密码

      ssh root@192.168.16.85

       

 

作业

  • 写脚本

    idhostname
    1 192.168.16.85
    2 192.168.16.84
    3 192.168.16.83
    1. 运行脚本
    2. 要求用户输入要在远程服务器执行的命令。
    cmd = input('请输入要执行的命令:') # ifconfig

    3. 通过pymysql模块去数据库中读取主机列表。
    4. 在所有的主机中执行此命令,并打印出每台服务器上执行命令结果。

    知识点:for循环逐一执行;线程池可以提供并发。

    前提:公钥和私钥自己生成并上传。

  •  

 

1、什么是前后端分离
复制代码
 前端:整个页面显示以及页面的交互逻辑,用ajax和node作为交互。其中node作为中间层
 后端:提供api接口,利用redis保存session,与数据库交互
 ​
 步骤:
 1)客户端(浏览器)向node请求页面交互。
 2)node向后端(这里用java)转发请求。java在发送请求到数据库。
 3)java返回结果给node。node返回页面,提供数据。
 ​
 node:
     node主要是为了分层开发,前端不需要知道后端是怎么提供数据,怎么操作。后端也不需要知道node是怎么操作,前端是怎么部署。前端可以利用node自己作处理。
 node本身有着异步,非阻塞I/o。在处理并发量比较大的数据请求上有很大的优势。
复制代码
2、什么是restful规范
复制代码
 restful规范是一套规则,用于API中之间进行数据交换的约定。
 它的具体规则有:
 1、https代替http,保证数据传输时的安全
 2、在url中一般要体现api标识,这样看到url就知道他是一个api
     建议:https://www.zdr.com/api/...(不会存在跨域问题)
 3、在接口中要体现版本,可放在url中也可以放在请求头中
     建议:https://www.zdr.com/api/v1/...
 4、restful也称为面向资源编程,视网络上的一切都是资源,对资源可以进行操作,所以一般资源都用名词
 5、如果要加入一些筛选条件,可以添加在url中
     https://www.zdr.com/api/v1/user/?page=1&type=9
 6、根据method请求方法不同做不同操作
     get/post/put/patch/delete
 7、根据请求方法不同返回不同的值
     get全部/post返回添加的值/put/patch/delete不返回值
 8、给用户返回状态码
     - 200——成功
     - 300——301是永久重定向,302是临时重定向
     - 400——403拒绝中间件的csrftoken认证 /404找不到
     - 500——服务端代码错误
 9、操作异常时,要返回错误信息
     {
         error: "Invalid API key"
     }
 10、对于下一个请求要返回一些接口: Hypermedia AP
     {
         'id':2,
         'name':'alex',
         'age':19,
         'depart': "http://www.luffycity.com/api/user/30/"
     }
复制代码
3、模拟浏览器进行发送请求的工具
postman
4、查找模板的顺序
 优先查找根目录下:templates
 根据app的注册顺序去每个app的templates目录中找
5、什么是drf组件
drf的全称是Django RESTful Framework
 它是一个基于django开发的组件,本质是一个django的app
 drf可以帮我们快速开发出一个遵循restful规范的程序
6、drf组件提供的功能
复制代码
 免除csrf认证
 视图(三种:(1)APIView,(2)ListAPIview,(3)ListModelMixin)
 版本处理
 认证
 权限
 节流(频率限制)
 解析器
 筛选器
 分页
 序列化和数据校验:可以对QuerySet进行序列化,也可以对用户提交的数据进行校验——展示特殊的数据
     depth
     source:无需加括号,在源码内部会去判断是否可执行,如果可执行自动加括号。【多对一、一对一/choice】
     SerializerMethodField定义钩子方法【多对多】
 渲染器:可以帮我们把json数据渲染到drf自己的页面上。
复制代码
7、drf继承过哪些视图类?以及他们之间的区别?
复制代码
 第一种:APIView
     第一种遵循了CBV的模式,里面的功能比较多但是需要自己写的代码也有很多
     提供了免除csrf认证,版本处理、认证、权限、节流、解析器、筛选器、分页、序列化、渲染器
 ​
 ​
 第二种:ListAPIView,RetrieveAPIView,CreateAPIView,UpdateAPIView,DestroyAPIView
     第二种则在第一种的基础上,封装了许多我们需要自己的写的代码,许多功能的实现只需要给专属的变量名赋值就可以实现该功能
 ​
 ​
 第三种:GenericViewSet、ListModelMixin,RetrieveModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin
     第三种则重构了APIView中的as_view()方法,结合请求方法和不同Mixin类的方法名从而进行执行不同的功能。与前面两种最主要的区别是url路由中as_view()方法中需要传值。
     目前使用的主要目的是把第二种的bug(查询全部数据的功能和查询单个数据的功能无法在一个类中实现)实现在一个类中!
复制代码
8、GenericAPIView视图类的作用
复制代码
 总结:GenericAPIView主要为drf内部帮助我们提供增删改查的类LIstAPIView、CreateAPIView、UpdateAPIView、提供了执行流程和功能,
我们在使用drf内置类做增删改查时,就可以通过自定义 静态字段(类变量)或重写方法(get_queryset、get_serializer_class)来进行更高级的定制。 他提供了一些规则,例如: ​ 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...
复制代码
9、drf版本的实现过程?
复制代码
 # drf自带的版本类
     "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
 # 允许出现的版本
     "ALLOWED_VERSIONS": ['v1', 'v2'],
 # 如果没有传版本,可以使用默认版本
     default_version = api_settings.DEFAULT_VERSION
 # 设置url中获取版本的变量,默认是version
     version_param = api_settings.VERSION_PARAM
     
    当前端来请求时,执行了as_views()方法,如果设置了全局版本或者进入了设置了版本的功能函数,则会先执行APIView类中的dispatch方法,之后再执行initial方法,然后进入了self.determine_version方法,
里面会先判断是否有versioning_class,如果没有就返回(None,None),就代表没有版本,如果有就执行versioning_class(URLPathVersioning)类中的determine_version方法,它会返回版本,里面会判断,
如果获取到的version为空则返回默认版本,并且还要判断版本是否存在允许出现的版本列表中,返回版本之后,再把版本号和版本类分别赋值给request.version和request.versioning_scheme
复制代码
10、drf组件认证的实现过程?
复制代码
当用户进行登录的时候,运行了登录类的as_view()方法,
 1、进入了APIView类的dispatch方法
 2、执行了self.initialize_request这个方法,是重定义request,并且得到了自己定义的认证类对象
 3、执行self.initial方法中的self.perform_authentication,里面运行了user方法
 4、再执行了user方法里面的self._authenticate()方法
 5、然后执行了自己定义的类中的authenticate方法,自己定义的类继承了BaseAuthentication类,里面有  authenticate方法,如果自己定义的类中没有authenticate方法会报错。
 6、把从authenticate方法得到的user和auth赋值给user和auth方法
 7、这两个方法把user和auth的值赋值给了request.user:是登录用户的对象,request.auth:是认证的信息字典
复制代码

11、drf组件权限的实现过程?
复制代码
 当用户执行一个业务的时候,运行了as_view方法
 1、进入了APIView类的dispatch方法
 2、进入self.initial方法中的self.check_permissions(request)方法
 3、里面执行了for循环,把每个权限类实例化对象,
 4、执行自己定义的权限类里面的has_permission方法,里面会判断request.user是否存在
 5、不存在就返回False,存在就返回True
 6、之后执行self.permission_denied报错方法,返回的是False就报错,可以自定义报错信息,在has_permission方法中写message = {"status": False, "error": "登录成功之后才能评论"},
就实现了自定义报错 7、如果返回的是True就让他进入功能
复制代码

12、drf组件中节流的实现方式?
复制代码
匿名用户通过ip地址来控制访问频率,已登录用户通过id来控制
 首先要设置配置文件:
 # 也可以设置全局,
     "DEFAULT_THROTTLE_CLASSES":["rest_framework.throttling.AnonRateThrottle",]
 # 设置访问频率——一分钟10次
     "DEFAULT_THROTTLE_RATES": {
             "anon":"10/m"
         }
 - 实现原理
     把所有登录记录时间放在一个列表中,当用户请求网页的时候,用现在的时间减去约束的时间间隔,然后把小于这个时间记录排除,再计算出时间间隙的记录条数,
如果其中的条数小于规定的条数则可以访问并且把当前时间添加进列表中,如果大于或等于则不让其访问。 - 具体流程 当用户请求网页的时候,后台允许该界面的url中的as_views(),运行源码的APIView中的dispatch方法,运行initial方法,里面的check_throttles方法,
循环运行节流类中的allow_request方法,但是AnonRateThrottle等类中没有,去执行SimpleRateThrottle类中的allow_request方法,里面就是实现原理中的代码,
如果可以访问返回True,如果不让访问则返回False,之后返回check_throttles,如果是False则运行SimpleRateThrottle类中的wait方法得到需要等待的时间在页面上显示!
复制代码

13、序列化时many=True和many=False的区别?
复制代码
在使用APIView时,数据展示的时候序列化多个数据的时候用many=True,序列化单个数据的时候用many=False
 ​
 案例:
 category_all = models.Category.objects.all()
 ser_category = serializer.HomeCategorySerializer(instance=category_all, many=True)
 ​
 article_obj = models.Article.objects.filter(id=pk).first()
 ser = serializer.OneArticleSerializer(instance=article_obj, many=False)
复制代码
14、drf各个功能的使用程度,不代表重要程度
复制代码
*****
     解析器:request.query_parmas/request.data
     视图
     序列化
     渲染器:Response
 ​
 ****
     request对象封装
     版本处理
     分页处理
 ***
     认证
     权限
     节流
复制代码
15、什么是jwt? 它的优势是什么?
复制代码
 jwt的全称是json web token, 一般用于用户认证
 jwt的实现原理:
     - 用户登录成功之后,会给前端返回一段token。
     - token是由.分割的三段组成。
         - 第一段header:类型+算法+base64url加密
         - 第二段paylod:用户信息+超时时间+base64url加密
         - 第三段sign:hs256(前两段拼接)加密 + base64url
     - 以后前端再次发来信息时
         - 超时验证
         - token合法性校验
 优势:
     - token只在前端保存,后端只负责校验。
     - 内部集成了超时时间,后端可以根据时间进行校验是否超时。
     - 由于内部存在hash256加密,所以用户不可以修改token,只要一修改就认证失败。
复制代码
16、装饰器
复制代码
 应用区域:
 - 在django中csrftoken认证中使用了
 - 在flask中的路由url中也使用了
 ​
 标准装饰器:
 def outer(func):
     def inner(*args,**kwargs):
         return func(*args,**kwargs)
     return inner
 ​
 @outer
 def index(a1):
     pass
 ​
 index()
复制代码
17、面向对象中基于继承+异常处理来做的约束
复制代码
 在drf的版本、认证、权限、节流的源码中都大量使用了面向对象中的继承和异常处理 
 ​
 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
复制代码
18、面向对象封装
复制代码
 drf源码中的APIView的dispatch中有个self.initialize_request,它返回了一个Request类,它封装了django的request和认证对象列表等其他参数
 事例:
 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
         )
复制代码
19、面向对象继承
复制代码
 django中源码大量使用了面向对象的继承
 尤其是drf中的继承关系最为明显
 事例:
 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()
复制代码
20、反射 
复制代码
 应用场景:
 1、django中的View类的dispatch通过接收到的请求方法变为小写从而使用反射得到类中的相对应方法,比如get方法。
 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)
 ​
 ​
 2、django中的settings配置文件的源码也使用了反射,并且结合了
 import importlib
 self.SETTINGS_MODULE = settings_module  # 获取到settings文件的路径
 mod = importlib.import_module(self.SETTINGS_MODULE)  # 通过importlib.import_module获取到settings文件对象
 for setting in dir(mod): # 循环获取到settings文件对象里面的属性
     if setting.isupper(): # 得到大写的属性名
     setting_value = getattr(mod, setting)  # 得到属性值比如中间件等其他配置属性
复制代码
21、ajax请求写法
复制代码
 可模拟任何请求方式向后端发送请求
 ​
 $.ajax({
     url:'地址',
     type:'GET',
     data:{...},
     success:function(arg){
         console.log(arg);
     }
 })
复制代码
22、跨域问题

浏览器具有”同源策略的限制“,导致 发送ajax请求 + 跨域 存在无法获取数据,只有ajax才能导致跨域,html中的src不会,导致跨域的原因有域名不同或者不同端口、http与https互相发送

  • 简单请求,发送一次请求

  • 复杂请求,先options请求做预检,然后再发送真正的请求

23、如何解决ajax+跨域?
 CORS(跨域资源共享):是一种使用额外的 HTTP 头部来允许浏览器可以在一个不同域的网站内获取另一个域下的服务器资源的机制。
 ​
 本质是设置响应头。
24、常见的HTTP请求方法
 get:让后端传给前端想要的数据
 post:前端传数据给后端让其添加记录
 put:前端传数据和筛选数据的依据给后端让其更新记录
 patch:前端传局部数据和筛选数据的依据给后端让其更新局部记录
 delete:前端传筛选数据的依据给后端让其删除记录
 options:是跨域问题中的复杂请求预检的请求
25、http请求中Content-type请求头
复制代码
 情况一:
     content-type:x-www-form-urlencode
     name=alex&age=19&xx=10
     request.POST和request.body中均有值
     
 情况二:
     content-type:application/json
     {"name":"Alex","Age":19}
     request.POST没值
     request.body有值
复制代码
26、django中F查询
 F可以提取某个字段的值,可以用来比较两个字段值的判断,可以更新某个字段的值
 ​
 ​
 Q用来表示条件,使用Q对象来组成各种关系的条件,|=or
27、django中获取空Queryset
models.User.object.all().none()
28、基于django的fbv和cbv都能实现遵循restful规范的接口
复制代码
 FBV:
 def user(request):
     if request.method == "GET":
     pass
 ​
 CBV:
 class UserView(View):
     def get():
         pass
      
     def post():
         pass
 ​
 FBV和CBV的区别:
 FBV顾名思义就是函数处理请求,代码冗余比较多,不是面向对象编程
 CBV则是使用类中的不同方法来处理请求,迎合了python所推崇的面向对象编程思想。
     相比FBV的优点:
     1、提高了代码的复用性,可以使用面向对象的计算,比如Mixin(多继承)
     2、可以用不同的函数针对不同的http请求方法处理,而不是通过过多的if判断,提高了代码的可读性

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2020-01-04 16:51  向往1  阅读(871)  评论(0)    收藏  举报

导航

……