drf面试题及总结
drf面试题及总结
1.什么是前后端分离
2.什么是restful规范
3.模拟浏览器进行发送请求的工具
4.查找模板的顺序
5.什么是drf组件
6.drf组件提供的功能
7.drf继承过哪些视图类?以及他们之间的区别?
8.GenericAPIView视图类的作用
9.drf版本的实现过程?
10.drf组件认证的实现过程?
11.drf组件权限的实现过程?
12.drf组件中节流的实现方式?
13.序列化时many=True和many=False的区别?
14.drf各个功能的使用程度,不代表重要程度
15.什么是jwt? 它的优势是什么?
16.装饰器
17.面向对象中基于继承+异常处理来做的约束
18.面向对象封装
19.面向对象继承
20.反射
21.ajax请求写法
22.跨域问题
23.如何解决ajax+跨域?
24.常见的HTTP请求方法
25.http请求中Content-type请求头
26.django中F查询
27.django中获取空Queryset
28.基于django的fbv和cbv都能实现遵循restful规范的接口
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判断,提高了代码的可读性
drf面试题及总结的更多相关文章
- python学习之旅
python学习分类 python基础 +- day01——python初始.变量.常量.注释.基础数据类型.输入.if day02——while.字符串格式化.运算符.编码初识 day03—— ...
- python面试导航
python面试题库 python基础 等待更新中 函数 等待更新中 面向对象 等待更新中 高级编程 等待更新中 数据库 等待更新中 前端&django 等待更新中 crm 等待更新中 drf ...
- python 全栈开发,Day104(DRF用户认证,结算中心,django-redis)
考试第二部分:MySQL数据库 6. MySQL中char和varchar的区别(1分) char是定长,varchar是变长. char的查询速度比varchar要快. 7. MySQL中va ...
- python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)
昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...
- .NET面试题系列[8] - 泛型
“可变性是以一种类型安全的方式,将一个对象作为另一个对象来使用.“ - Jon Skeet .NET面试题系列目录 .NET面试题系列[1] - .NET框架基础知识(1) .NET面试题系列[2] ...
- 关于面试题 Array.indexof() 方法的实现及思考
这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...
- 对Thoughtworks的有趣笔试题实践
记得2014年在网上看到Thoughtworks的一道笔试题,当时觉得挺有意思,但是没动手去写.这几天又在网上看到了,于是我抽了一点时间写了下,我把程序运行的结果跟网上的答案对了一下,应该是对的,但是 ...
- 从阿里巴巴笔试题看Java加载顺序
一.阿里巴巴笔试题: public class T implements Cloneable { public static int k = 0; public static T t1 = new T ...
- JAVA面试题
在这里我将收录我面试过程中遇到的一些好玩的面试题目 第一个面试题:ABC问题,有三个线程,工作的内容分别是打印出"A""B""C",需要做的 ...
随机推荐
- Qt中的强制类型转换
在C++开发中经常要进行数据类型的强制转换. 刚开始学习的时候,直接对基本数据类型强制类型转换,如float fnum = 3.14; int num = (int)fnum; 随着C++标准的发展, ...
- WorkFlow三:配BO对象,事件触发工作流
1.新建个BO对象的字段. 2.新建取数函数: 3.运行事物代码SWO1新建BO对象. 4.新建关键字段: 5.新建BO对象的事件: 6.添加处理方法: 6.调整对象状态,这里是本地对象,不需要释放, ...
- Shell 编程 数组
本篇主要写一些shell脚本数组的使用. 数组定义 数组名=(value0 value1 vlaue2 ...) 数组名=([0]=value [1]=value [2]=vlaue ...) 列表名 ...
- Leetcode——2. 两数相加
难度: 中等 题目 You are given two non-empty linked lists representing two non-negative integers. The digit ...
- 201871020225-牟星源《面向对象程序设计(JAVA)》第二周学习总结
正文: 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-dai ...
- 关于selectpicker的多选问题
刚开始拿到这个需要求的时候,我时很没有头绪的,再前期做的时候是将这个多选的作为一个数组,传入到后端,然后再插入数据库中,然后根据关系表查询,因为但是考虑显示的问题,不知道怎么将多选的数据显示出来,我就 ...
- 【Mybatis】拼接表名
- java 8 学习一(概述)
学习java8的新特性之前,简单看了下从java5开始历代版本的新特性,都是别人总结的. java5.java6.java7.java8的新特性 http://blog.csdn.net/samjus ...
- [SDOI2018]物理实验 set,扫描线,旋转坐标系
[SDOI2018]物理实验 set,扫描线,旋转坐标系 链接 loj 思路 先将导轨移到原点,然后旋转坐标系,参考博客. 然后分线段,每段的贡献(三角函数值)求出来,用自己喜欢的平衡树,我选set. ...
- C函数之readlink
函数原型; #include<unistd.h> ssize_t readlink(const char *path, char *buf, size_t bufsiz); 函数说明: r ...