• 常见的面试题


    一、Django的请求生命周期

      1.wsgi,它就是socket的服务端,用于接收用户请求并将请求进行初次封装,然后讲求交给(Flask,Django)进行二次封装。

      2.中间件,帮助我们对请求进行校验或在请求对象中添加其他相关数据,例如:csrf、request.session

      3.路由匹配

      4.视图函数,在视图函数中进行业务逻辑的处理,可能涉及到:ORM、templates ==>>渲染

      5.中间件,对响应的数据进行处理。

      6.wsgi,将响应的内容发给浏览器。

      Django的流程图:

    二、什么是wsgi?  

    web服务网关接口,wsgi是一个协议,实现该写一个的模块:
    - wsgiref
    - werkzeug
    实现其协议的模块本质上就是socket服务端用于接收用户请求,并处理。
    一般web框架基于wsgi实现,这样实现关注点分离。

    wsgiref示例:
    from wsgiref.simple_server import make_server
     
    def run_server(environ, start_response):
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]
                 
                 
    if __name__ == '__main__':
        httpd = make_server('127.0.0.1', 8000, run_server)
        httpd.serve_forever()
            
    werkzeug示例:
    from werkzeug.wrappers import Response
    from werkzeug.serving import run_simple
    
    def run_server(environ, start_response):
        response = Response('hello')
        return response(environ, start_response)
    
    if __name__ == '__main__':
        run_simple('127.0.0.1', 8000, run_server)

    三、什么是HTTP协议?

      HTTP协议就是一种传输数据的格式,是基于TCP的之上的。原来学习django框架,是从socket服务端开始学起。

      自己创造一个socket服务器来充当网站,浏览器充当socket客户端。

      更能够明白http协议到底是什么:

      ----- 请求头  请求体

      ----- 响应头  响应体

      一次请求响应后,断开链接。(无状态,短连接)

    四、常见的请求头

      - Content-Type 
      - User-Agent:      值得不同,返回不同的页面。(根据设备)
      - referer:      可以做图片防盗链。
      - Host:          当前域名
      - cookies:     携带在请求头里面

    五、常见的请求体?

      Form表单提交:
        POST /index http1.1 host:www.luffycity.com... username=alex&password=123&...
      Ajax请求:
        POST /index http1.1 host:www.luffycity.com... username=alex&password=123&...
        POST /index http1.1 host:www.luffycity.com... {“username”:"alex","password":123}

      补充:django中获取请求体
         - request.POST   只能获取这种可是的(nusername=alex&password=123)
         - request.body   能够获得 ({“username”:"alex","password":123})

      常见的请求方法:

        GET/POST/DELETE/PUT/PATCH/OPTIONS

    六、中间件

      中间件有五种方法:

        process_request(self,request)
        process_view(self, request, callback, callback_args, callback_kwargs)
        process_template_response(self,request,response)
        process_exception(self, request, exception)
        process_response(self, request, response

      中间件的应用场景:

        1.登录认证,不再需要在每个函数中添加装饰器。

        2.权限,当用户登录的时候获得当前用户的所有权限并放入session,然后再次访问其他页面,获取当前url并在session中进行匹配。如果没有匹配成功,则在中间件返回“无权访问”

        3.跨域

        4.使用中间件做过什么?

          (1)内置  csrf   sesson

          (2)自定义   登录认证  权限  cors

    七、为什么会有跨域?

      浏览器具有同源策略才出现跨域。

        同源策略:

          开放:src

          禁止:ajax

      解决跨域的两种方法:

        1、jsonp:在客户端动态的创建一个script标签

          (1) 客户端:创建一个

            <script src='http://www.jxntv.cn/data/jmd-jxtv2.html'></script>

            <script>
               function func(arg){
                alert(arg);
                  }
             </script>

          (2) 服务端:接收到请求并处理返回值"func('success')"相当于:

            <script>

              func('success')
            </script>

            必须与上边一致,而且jsonp只能发送GET请求

        2、cors:设置响应头

          (1)简单请求

          (2)复杂请求

            options 请求做预检

            PUT/POST

      应用:本地测试前后端分离时使用。

      在Django中的解决方案:

        1、中间件中设置响应头

        2、Django中的一个第三方组件:cors

      补充Ajax:  

        jQuery Ajax:
          $.ajax({
              ...
          })
        原生Ajax:XMLHttpRequest对象:
          var xhr = new XMLHttpRequest()

          xhr.onreadystatechange = function(){
            if(xhr.readyState == 4){
              // 已经接收到全部响应数据,执行以下操作
              var data = xhr.responseText;
              console.log(data);
            }
          };

          xhr.open('POST', "/test/", true);

          // 设置请求头
          xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset-  UTF-8');

          // 发送请求
          xhr.send('n1=1;n2=2;');

    八、视图

      在本质的上FBV和CBV是一样的

      区别:

      FBV:url----->函数(自己定义)

      CBV:   url----->view (继承的类)

      继承的类:

        class View(object): 

        class APIView(View):

        class GenericAPIView(views.APIView):

        class GenericViewSet(ViewSetMixin, generics.GenericAPIView)

        class ModelViewSet(mixins.CreateModelMixin,

                 mixins.RetrieveModelMixin,

                 mixins.UpdateModelMixin,

                   mixins.DestroyModelMixin,

                  mixins.ListModelMixin,

                 GenericViewSet):

     九、restful规范

      restful是一个规范,规定API如何编写,通过它可以让我们api更加简洁方便维护。

      例如,最直观的:

        method:   get/post/put/delete

        原来都是在url中设置的。

      除此之外还有:

        (1) api 

        (2)版本

        (3)名词(面向资源编程)

        (4)条件

        (5)响应式设置状态码

        (6)返回值    

          GET: 所有列表
            {
              code: 10000,
              data: [
                {'id':1,'title':'xx'},
                {'id':1,'title':'yy'},
                {'id':1,'title':'zzz'},
                  ]
              }

          POST: 返回新增的数据
            {'id':1,'title':'xx'}

            https://www.luffycity.com/api/v2/salary/1/
          GET: 获取单条数据
            {'id':1,'title':'xx'}
          PUT:更新
            {'id':1,'title':'xx'}
          PATCH: 局部更新
            {'id':1,'title':'xx'}
          DELETE:删除

        (7)错误信息

        (8)hypermedia link

      什么是接口?

        URL

        约束:约束继承(实现)了它的类中必须含有的方法

    十、django rest framework 框架

      作用:快速搭建基于restful规定的接口

       1、路由

           (1)可以通过as_view传参数,根据请求方式不同执行相应的方法

           (2)可以在url中设置一个结尾,类似于:.json

       2、视图

             帮助了开发者提供了一些类,并在类中提供了多个方法以供我们使用

       3、版本

         在url中设置version参数,用户请求时候传入参数。在request.version中获取版本,根据版本不同做不同处理

       4、认证  

          写一个类并注册到认证类,在类的authtocate方法中编写认证逻辑

              认证成功(user,auth) 

            raise AuthticateFaild(....)

              None

       5、权限

             写一个类并注册到权限类,在类的的has_permission方法中编写认证逻辑。
                          True
                False

       6、访问频率的限制   

          - 访问频率控制原理:
            匿名:
            1.1.1.1:[时间,时间,时间,时间,]
            登录:
            user:[时间,时间,时间,时间,]

            默认将访问记录放在缓存中:redis/memcached

                写一个类并注册到频率类,在类的的 allow_request/wait 方法中编写认证逻辑。

              allow_request
              True
               False 如果返回False,那么就要执行wait

       7、解析器

        根据ContentType请求头,选择不同解析器对 请求体中的数据进行解析。

          POST /index/ http1.1. host:11.11.11.11 Content-Type:url-formendo.... user=alex&age=123
          POST /index/ http1.1. host:11.11.11.11 Content-Type:application/json {....}

       8、序列化   

          对queryset序列化以及对请求数据格式校验。 

          from rest_framework.serializers import Serializer

          class XX(Serializer):
          pass
          ser =XX(queryset,many=True) # ListSerializer对象
          ser =XX(obj, many=False) # XX对象

          - 列表生成式

          - 根据字符串的形式,自动导入模块并使用反射找到模块中的类【参考:s9day108】。

       9、分页   

             对从数据库中获取到的数据进行分页处理: SQL -> limit offset
          根据页码:http://www.luffycity.com/api/v1/student/?page=1&size=10
          根据索引:http://www.luffycity.com/api/v1/student/?offset=60&limit=10
          根据加密:http://www.luffycity.com/api/v1/student/?page=erd8

          页码越大速度越慢,为什么以及如何解决?
            原因:页码越大向后需要扫描的行数越多,因为每次都是从0开始扫描。
            解决:
               限制显示的页数
               记录当前页数据ID最大值和最小值,再次分页时,根据ID现行筛选,然后再分页。

       10、渲染器

          根据URL中传入的后缀,决定在数据如何渲染到到页面上。

    十一、ORM的补充

        a. 需求: 只取某n列
          queryset=[ {},{}]
          models.User.objects.all().values( 'id','name')

          queryset=[ (),()]
          models.User.objects.all().values_list( 'id','name')

          queryset=[ obj,obj]

        b. - only
          result = models.User.objects.all().only('id','name','age')

        c. - defer
          # result = models.User.objects.all().defer('id','name','age')
          for item in reuslt:
          print(item.id,item.name,item.age)

          示例:
          class Depart(models.Model):
    5个部门
          title = models.CharField(...)

          class User(models.Model): 10个用户
          name = models.CharField(...)
          email = models.CharField(...)
          dp = models.FK(Depart)

          1.之前:11次单表查询

          result = User.objects.all()
          for item in result:
          print(item.name,item.dp.title)

          2. seleted_related,主动做连表查询(1次链表)

          result = User.objects.all().seleted_related('dp')
          for item in result:
          print(item.name,item.dp.title)

          问题:如果链表多,性能越来越差。

          3. prefetch_related:2次单表查询
          # select * from user ;
          # 通过python代码获取:dp_id = [1,2]
          # select * from depart where id in dp_id
          result = User.objects.all().prefetch_related('dp')
          for item in result:
          print(item.name,item.dp.title)

        注:数据量比较大,不会使用FK,允许出现数据冗余。

         - select_related,连表操作,相当于主动做join
        - prefeth_related,多次单表操作,先查询想要的数据,然后构造条件,如:id=[1,2,3],再次查询其他表根据id做条件。
        - only
        - defer
        - F 更新数据库字段
        - Q 构造复杂条件
        - 通过ORM写偏原生SQL:
        - extra
          Entry.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
          Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
          Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
          Entry.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])

        - raw
          # 执行原生SQL
          models.UserInfo.objects.raw('select * from userinfo')

          # 如果SQL是其他表时,必须将名字设置为当前UserInfo对象的主键列名
          models.UserInfo.objects.raw('select id as nid from 其他表')

          # 为原生SQL设置参数
          models.UserInfo.objects.raw('select id as nid from userinfo where nid>%s', params=[12,])
          name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
          Person.objects.raw('SELECT * FROM some_other_table', translations=name_map)
        - 原生SQL

          from django.db import connection, connections
          cursor = connection.cursor() # cursor = connections['default'].cursor()
          cursor.execute("""SELECT * from auth_user where id = %s""", [1])
          row = cursor.fetchone() # fetchall()/fetchmany(..)
          PS: 选择数据库
          queryset = models.Course.objects.using('default').all()

            

      

  • 相关阅读:
    tgttg
    在OpenStack虚拟机实例中创建swap分区的一种方法
    产品:我想要的产品是网络存储+网络备份
    《哪来的天才?》读书笔记——天才源于练习,而且是针对性的练习
    一万小时理论的解读(神贴真开眼界:有意识的刻苦训练是必须的,要有精神动力,还必须有及时的反馈,对实力占优的活动比较有效;玩这样的活动是不行的)
    Cross-compiling Qt Embedded 5.5 for Raspberry Pi 2
    MSYS2的源配置
    关于iOS 5 Could not instantiate class named NSLayoutConstraint错误
    BAT线下战争:巨额投资或培养出自己最大对手(包括美团、58、饿了么在内的公司都在计划推出自己的支付工具和金融产品,腾讯只做2不做O)
    欢聚移动互联时代 在腾讯的夹缝中低调崛起
  • 原文地址:https://www.cnblogs.com/xu1686318405/p/9122290.html
Copyright © 2020-2023  润新知