Drf06 /drf总结
目录
1. restful规范
restful是一套规则,是程序间进行数据传输的一种约定
1.建议用https代替http,为了保证数据的安全
2.在url中添加api标识,这样看到url就知道是一个api,建议放在域名后面,这样不会存在跨域问题
3.在接口中体现版本信息,方便于版本的迭代,
4.restful也称面向资源编程,视网上的一切都是资源,所以一般资源都用名词
5.如果要添加一些筛选条件,可以写在url中
6.根据method不同做不同的操作
7.返回给用户状态码
8.对不同请求返回不同的数据
9.如果有异常返回错误信息
10.对于下一个请求要返回一个接口
2. drf组件认证的实现过程?
1.当用户请求过来时,执行dispatch,通过initialize_request方法,
2.找到认证的所有类并实例化成对象列表,然后将对象列表封装到新的request对象中。
3.执行下面的initial方法,经过认证的request.user方法
4.在内部会循环认证的对象列表,并执行每个对象的authenticate方法,该方法用于认证,返回值有三种,①抛出异常②返回None③返回一个元组
5.返回元组的两个值分别赋值给request.user和request.auth
3. drf组件中权限的实现过程?
1.当用户请求过来时,先执行dispatch方法,通过initial方法执行check_permissions方法
2.找到权限的所有类并实例化成对象列表
3.循环该实例化对象列表,执行每个对象的has_permission方法
4.返回True和False进行权限的认证,可定制错误信息
4. drf组件中节流的实现方式?
- 实现原理
来访问时:
1.获取当前时间 100121280
2.100121280-60 = 100121220,小于100121220所有记录删除
3.判断1分钟以内已经访问多少次了? 4
4.无法访问
停一会
来访问时:
1.获取当前时间 100121340
2.100121340-60 = 100121280,小于100121280所有记录删除
3.判断1分钟以内已经访问多少次了? 0
4.可以访问
- 具体流程
请求来时会执行allow_follow方法,
会用self.key获取请求用户的ip,再用self.history根据用户的ip获取其访问的记录,
获取当前的时间,用当前的时间减去设定的时间段,
循环该用户访问的记录,将不在该时间段的记录pop掉,
通过len判定该时间段已经访问了多少次,超过限定次数会返回false
匿名用户是通过ip进行访问限制,登录用户通过用户的id进行访问限制
5. 什么是jwt?优势?
一般用于做用户认证(登录)使用的技术。
jwt的实现原理:
- 用户登录成功之后,会给前端返回一段token。
- token是由.分割的三段组成。
- 第一段:类型和算法信息 -- header
- 第二段:用户信息+超时时间 -- payload
- 第三段:hs256(前两段拼接)加密 + base64url -- sign
- 以后前端再次发来信息时
- 超时验证
- token合法性校验
优势:
- token只在前端保存,后端只负责校验。
- 内部集成了超时时间,后端可以根据时间进行校验是否超时。
- 由于内部存在hash256加密,所以用户不可以修改token,只要一修改就认证失败。
6.drf框架
drf是一个基于django开发的组件,本质是一个django的app。
drf可以为我们快速开发出一个遵循restful规范的程序。
1.drf为我们提供了一大堆视图,ListAPIView,RetrieveAPIView,DestroyAPIView,UpdateAPIView,CreateAPIView,可以帮我们快速的进行增删改查,但是只能完成最基本的对表格的增删改查,想要更多的功能可以重写视图的方法
2.版本的处理
3.认证
4.权限
5.截流(频率限制)
6.视图过后进入解析器,有request.data,reqeust.querysetparams.get('pk')
7.序列化,可以对用户数据进行校验以及序列化
8.筛选器
9.分页
10.渲染
7.写视图的方法
-
第一种:原始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 相关知识点梳理
-
装饰器
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()
-
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)
-
面向对象中基于继承+异常处理来做的约束
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(arg){ console.log(arg); } })
-
浏览器具有 "同源策略的限制",导致
发送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>
-
如何解决ajax+跨域?
CORS,跨站资源共享,本质:设置响应头。
-
常见的Http请求方法
get post put patch delete options
-
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有值。
-
django中F查询
-
django中获取空Queryset
models.User.object.all().none()
-
基于django的fbv和cbv都能实现遵循restful规范的接口
def user(request): if request.metho == 'GET': pass class UserView(View): def get()... def post...
-
基于django rest framework框架实现restful api的开发。
- 免除csrf认证 - 视图(APIView、ListAPIView、ListModelMinx) - 版本 - 认证 - 权限 - 节流 - 解析器 - 筛选器 - 分页 - 序列化 - 渲染器
-
简述drf中认证流程?
-
简述drf中节流的实现原理以及过程?匿名用户/非匿名用户 如何实现频率限制?
-
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)来进行更高级的定制。
-
jwt以及其优势。
-
序列化时many=True和many=False的区别?
many=True 序列化多个数据 many=False 序列化单个数据
-
应用DRF中的功能进行项目开发
***** 解析器:request.query_parmas/request.data 视图 序列化 渲染器:Response **** request对象封装 版本处理 分页处理 *** 认证 权限 节流
- 基于APIView实现呼啦圈
- 继承ListAPIView+ GenericViewSet,ListModelMixin实现呼啦圈
-
jwt和传统的token的区别?
# 补充
传统的token会放在缓冲中,redis缓冲中,实际上不会放在数据库