drf1-1.5

drf 源码

1567937996087

#  CBV 类型的全是根据反射来的,基于反射实现根据请求方式不同,执行不同的方法
#  原理 :
    # a. 
    url - view()  - dispath
class StudentsView(View):
    def dispatch(self, request, *args, **kwargs):
        func = getattr(self, request.method.lower())
        ret = func(request, *args, **kwargs)  # 各个函数执行,以及参数 get()....
        return ret
    def get(self,request):
        return HttpResponse('GET')

cbv的运行流程

   def dispatch(self, request, *args, **kwargs):
        ret = super(StudentsView, self).dispatch(request, *args, **kwargs)
        return ret

1567938861888

继承: (多个类公用的功能,为了避免重复)

面试题

  1. django中间件

    • 中间件最多可以写几个方法:5个
    • process_request view response exception
    • render_template
  2. 执行流程

  3. 中间件做过什么?

    权限

    用户登陆验证

    django csrf_token 怎么实现的?(面试题)

    在view里面 : request view 都是在请求前

    • from django.views.decorators.csrf import csrf_exempt
    • csrf_excmpt免除csrf请求

    • 1567939934152

      process_view方法

      检查是否被@csrf_exempt(免除csrf认证)

      去请求体或cookie重获取token

      为什么是view,view之后才是请求执行,才能装饰器

CBV小知识点:

csrf时加到单独方法无效

class:...
# @csrf_exempt  # 这么加不行
# @method_decorator(csrf_exempt)
def post(self, request):
    return HttpResponse('POST')

必须加到dispath里面

 @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        func = getattr(self, request.method.lower())
        ret = func(request, *args, **kwargs)  # 各个函数执行,以及参数 get()....
        return ret

或者类上

@method_decorator(csrf_exempt, name='dispatch')
class StudentsView(View):

这样写可以少些一个 distpatch 方法

总结:

  • 本质 : 基于反射来实现
  • 流程 : 路由 view dispatch (反射)
  • csrf_token取消 不从中间件, 要加到类上或者dispatch csrf_exempt
  • 扩展
    • csrf
      • 基于中间件的proces_view
      • 装饰器给单独函数设置或者不适用

restful 规范 (建议)

开发前后端分离

a :
用户管理 http://www.oldboyedu.com/add_user/ ....

​ 返回值很多,返回值的时候,不好处理了

​ {

​ code:666,

​ }

b:

​ vue

​ $.ajax({})

#不好, 因为10张表 处理  ,就40条url了
# 规范 : 10个url , 用method来处理不同的

基于fbv写

# 1 根据method不同进行不同的处理
def order(request):
    if request.method == "GET":
        return HttpResponse('获取')
    if request.method == "add":
        return HttpResponse('获取')
    if request.method == "del":
        return HttpResponse('获取')
    if request.method == "update":
        return HttpResponse('获取')

基于cbv写

class orderView(View):
    def get(self,request,*args,**kwargs):
        return HttpResponse('获取')
    def post(self,request,*args,**kwargs):  # 创建
        return HttpResponse('获取')
    def put(self,request,*args,**kwargs):   # 更新
        return HttpResponse('获取')
    def delete(self,request,*args,**kwargs):
        return HttpResponse('获取')

2域名上区分(解决跨域问题):

​ www.luffycity.com

​ 子域名上区分 api.luffycity.com

url方式:

​ www.luffycity.com

​ www.luffycity.com/api

版本方式

www.luffycity.com/api/v1/#

3面向资源编程

网络上所有的东西都当成资源,

4尽量使用名词

5 method(5) put在服务器上更新,全部更新

​ patch :() 局部更新

6 过滤

www.luffycity.com/api/v1/?status=1

7 状态码

状态码和code结合着用, code表示的多,前端可能愿意处理

8 返回结果

1567942443696

9 h...自己去拼接url

以上可以不遵循, 视情况而定

restful api 规范都有什么? 谈谈你对他的认知

伪装成一个老手,讲故事

在使用他的时候,有些适应,有些不用 ,出现问题了,跨域了,

解决: cors

​ jsonp ..

在聊天, 不好,然后用了那个

2.djangorestframework 框架

pip3 install djangorestframework

带token可以执行操作

1567998500855

1567998490695

from rest_framework.views import APIView
from rest_framework.authentication import BaseAuthentication
from rest_framework import  exceptions
# 登录认证基于这个类实现
# dispatch->reuqest(封装)->认证(initial)->per():request.user->user->获取认证对象-->类对象--->触发异常或者是token(正常)  # 写了一个My的类,写了一个auth_calssess , 有的话就找本类的,没有就去父类里找
class Myauthentication(object):
    def authenticate(self,request):
        token = request._request.GET.get('token')
        if not token:
            raise exceptions.AuthenticationFailed('用户认证失败')
        return ('alex',None)
    def authenticate_header(self,val):
        pass
class DogView(APIView):
    # authentication_classes = [BaseAuthentication, ]  # 获取的是类的对象,
    authentication_classes = [Myauthentication, ]  # 获取的是类的对象,

    # self.dispatch
    def get(self, request, *args, **kwargs):
        ret = {
            'code': 1000,
            'msg': 'xxx'
        }
        return HttpResponse(json.dumps(ret), status=201)

    def post(self,request,*args,**kwargs):
        return HttpResponse('创建dog')
    def put(self,request,*args,**kwargs):
        return HttpResponse('更新dog')
    def delete(self,request,*args,**kwargs):
        return HttpResponse('删除dog')

基于这个类做的认真

dispatch

一.认证

a.认证

源码流程搞明白:搞不明白,加注释,入口

dispatch, 不仅会用,还知道原理

s7129

今日内容: 1 认证 2 权限 3 节流(访问频率控制) 4 版本

1568000733364

用到用户认证,需要先写一个类,然后,在写一个那个对象[,]

也可以全局用到

1568015600768

b.基本使用认证组件

  • 解决:
    • a.创建两张表
    • b.用户登陆(返回token并保存到数据库)

c. 源码

1568015825015

1568017683422

authentication_classes = [Authtication,]
#  self.dispatch 入口
def dispatch(self, request, *args, **kwargs):
   self.args = args
        self.kwargs = kwargs
        # 对原生的request进行加工(追加)
        # Request(request,parsers=self.get_parsers(),   authenticators=self.get_authenticators(),  negotiator=self.get_content_negotiator(),    parser_context=parser_context)
        # request(原生request,  [BaseAuthentication对象,], )
        # 获取原生request, self._request
        # 获取认证类的对象, request.authenticator
        # 1.封装Request
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?
        
 try:
            # 2. 认证成功,走反射
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            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

            response = handler(request, *args, **kwargs)
        
        # 认证失败,抛异常
        except Exception as exc:
            response = self.handle_exception(exc)
def initialize_request(self, request, *args, **kwargs):
    parser_context = self.get_parser_context(request)
    return Request(
        request,
        parsers=self.get_parsers(),
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )
    def get_authenticators(self):
        # self.authentication_classes = [foo,bar]
        return [auth() for auth in self.authentication_classes]
#对象,然后,自己写了这个类,和

如下:

from rest_framework.authentication import BaseAuthentication

# 重写这两个方法
def authenticate(self, request):
def authenticate_header(self, request): # pass就行
authentication_classes = [Authtication,]
# 用了drf , 对于重用的功能
class Authtication(object):
    def authenticate(self,request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败')
        # 在rest_framework内部会将整个两个字段赋值给request,以供后续操作使用
        return (token_obj.user, token_obj)

    def authenticate_header(self, request):
        pass
def initial(self, request, *args, **kwargs):
# 4.实现认证
    self.perform_authentication(request)
def perform_authentication(self, request):
    request.user

request.user在 Request.py里

@property
def user(self):
    if not hasattr(self, '_user'):
        with wrap_attributeerrors():
            # 获取认证对象, 进行一步步的认证
            self._authenticate()
    return self._user
[BaseAuthentication对象,]
 def _authenticate(self):
        # [BaseAuthentication对象,]
        # 循环认证类的所有对象
        for authenticator in self.authenticators:
            try:
                # 执行认证类的authenticate方法
                # 1.如果auth方法抛出异常,self._not_auth()执行
                # 2.有返回值,必须得是元祖(request.user, request.auth)
                # 3.返回None , 当前不处理,下一个认证来处理
                user_auth_tuple = authenticator.authenticate(self)
            except exceptions.APIException:
                self._not_authenticated()
                raise

            if user_auth_tuple is not None:
                self._authenticator = authenticator
                self.user, self.auth = user_auth_tuple
                return

        self._not_authenticated()

    def _not_authenticated(self):
        self._authenticator = None
        if api_settings.UNAUTHENTICATED_USER:
            self.user = api_settings.UNAUTHENTICATED_USER() # AnonymousUser
        else:
            self.user = None
        if api_settings.UNAUTHENTICATED_TOKEN:
            self.auth = api_settings.UNAUTHENTICATED_TOKEN() # None
        else:
            self.auth = None

执行了函数,函数就返回了

return (token_obj.user, token_obj) ,根据这里写的异常和元祖返回

d.源码配置 p=19

把写的类,返回元祖的认证的,返回异常的,写到setting里

然后所有的类默认都加了,不用在一个个单独写了

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.FirstAuthtication', 'api.utils.auth.Authtication' ]
}

全局都能用,局部不要用

class UserInfoView(APIView):
    """订单相关业务"""
    # 类似于中间件, 装饰器的处理restframework的方法,认证登录方法
    authentication_classes = []
    def get(self, request, *args, **kwargs):
        return HttpResponse('用户信息')

http://127.0.0.1:8000/api/v1/order/?token=851c293fe784dea90e079aad5d498f42

{
    "code": 1000,
    "msg": null,
    "data": {
        "1": {
            "name": "xifu",
            "age": 18,
            "gender": "男",
            "content": "..."
        },
        "2": {
            "name": "xifu2",
            "age": 18,
            "gender": "男",
            "content": "..."
        }
    }
}

http://127.0.0.1:8000/api/v1/order/

用户未登录

在最后 , _not_authenticated函数中

if api_settings.UNAUTHENTICATED_USER:
    self.user = api_settings.UNAUTHENTICATED_USER() # AnonymousUser
else:
    self.user = None

if api_settings.UNAUTHENTICATED_TOKEN:
    self.auth = api_settings.UNAUTHENTICATED_TOKEN() # None
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)


def reload_api_settings(*args, **kwargs):
    setting = kwargs['setting']
    if setting == 'REST_FRAMEWORK':
        api_settings.reload()

所以在settings里全局使用设置, USER , 和 TOKEN

authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

REST_FRAMEWORK = {
    # 全局使用的认证类
    # 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.auth.FirstAuthtication', 'app01.utils.auth.Authtication' ],
    'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.auth.FirstAuthtication', ],

    "UNAUTHENTICATED_USER":    None, # 匿名用户, request.user= None
    # 'UNAUTHENTICATED_TOKEN':None ,  # request.auth = None
}

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)

在rest_framework中settings里

api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS)
def reload_api_settings(*args, **kwargs):
    setting = kwargs['setting']
    if setting == 'REST_FRAMEWORK':
        api_settings.reload()

匿名是request.user = None

不是模态对话框

1568021678285

1568021689065

浏览器提供的,填完之后, 加密

1568021725261

基于django来实现的

不会用这些的,都是自定义来实现的

e.内置认证类

  • 认证类, 必须继承:from rest_framework.authentication import BaseAuthentication

  • 其他认证类:

梳理:

  1. 使用

    • 创建类:继承BaseAuthentication 实现auth..方法

    • 返回值:

      • None,下一个认证来执行
      • 抛异常 exceptions.AuthenticationFailed('用户认证失败') #from rest_framework import exceptions
      • (元素1,元素2) #元素1赋值给request.user;元素2赋值给request.auth
    • 局部使用

    • class Authtication(object):
          def authenticate(self,request):
              token = request._request.GET.get('token')
              token_obj = models.UserToken.objects.filter(token=token).first()
              if not token_obj:
                  raise exceptions.AuthenticationFailed('用户认证失败')
              # 在rest_framework内部会将整个两个字段赋值给request,以供后续操作使用
              return (token_obj.user, token_obj)
      
          def authenticate_header(self, request):
              pass
    • 全局使用

    • REST_FRAMEWORK = {
          # 全局使用的认证类
          # 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.auth.FirstAuthtication', 'app01.utils.auth.Authtication' ],
          'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.auth.FirstAuthtication', ],
      
          "UNAUTHENTICATED_USER": None,  # (没登录) 匿名用户, request.user= None   # 返回的是函数()所以写匿名函数
          # 'UNAUTHENTICATED_TOKEN':None ,  # request.auth = None
      }

2.源码流程

先走dispatch,request封装,走initial,找所有的对象,执行方法(两个)可以在setting中设置,但是api.settings为什么和settings相关联,不太懂

  • dispatch

    • 封装request

    获取定义的认证类(全局/局部),通过列表生成式创建对象

  • initial

    • perform_authentication
      • request.user(内部循环...)

后面的东西和这里的认证流程是一样的

二.权限

认证. user_type 有1234的时候可以访问

1568022484654

问题:不用视图不用权限可以访问

也是通过dispatch到4,

到check_permissions

遇到的问题1

在设置超级vip时,返回的值是1
if request.user.user_type != 1:
    return HttpResponse('无权访回')
    
AttributeError: 'NoneType' object has no attribute 'user_type'    

因为我权限里给他设置了

    # 全局使用的认证类
   # 'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.auth.FirstAuthtication', 'app01.utils.auth.Authtication' ],
     'DEFAULT_AUTHENTICATION_CLASSES': ['app01.utils.auth.FirstAuthtication', ],

返回的是空,而不是request.user和 request.auth,所以返回的是空

设置超级vip

根据每一个对象的user_type判断, 有的给他一个超级vip,别的默认不处理,(这里1是vip)

if request.user.user_type != 1:
    return HttpResponse('无权访回')

放入类中封装

# 认证过之后就开始权限认证了
class MyPermission(object):
    # self.dispatch
    def has_permission(self, request, view):
        # 把权限写入类里面
        if request.user.user_type != 1:
            return False
        return True  # 有权访问
class OrderView(APIView):    
    # 局部权限
    permission_classes = [MyPermission, ]

1568034481217

认证的所有的开启全局的之后,就没法处理auth了吗?

class MyPermission1(object):
    def has_permission(self, request, view):
        # 把权限写入类里面
        if request.user.user_type == 3:
            return False
        return True  # 有权访问
class UserInfoView(APIView):
    """订单相关业务(普通用户/vip)"""
    # 类似于中间件, 装饰器的处理restframework的方法,认证登录方法
    # authentication_classes = []
    permission_classes = [MyPermission1, ]
    def get(self, request, *args, **kwargs):
        return HttpResponse('用户信息')

完成了基本的权限了

看源码流程

dispatch
initial
check_permissions
              # [权限类的对象,权限类的对象,]
        for permission in self.get_permissions():
            # 通过per...为ture, 则not per..为false,不走, 而为false,则为ture,               走里面,抛异常
            if not permission.has_permission(request, self):
                self.permission_denied(
                    request, message=getattr(permission, 'message', None)
                )
                
def permission_denied(self, request, message=None):
"""
If request is not permitted, determine what kind of exception to raise.
"""
        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated()
        raise exceptions.PermissionDenied(detail=message)                

写成全局的

utils
    -auth.py
    -permission.py
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ['app01.utils.permission.SVIPPermission']     # 全局的
}
# 认证过之后就开始权限认证了
class SVIPPermission(object):
    # self.dispatch
    message = '必须是SVIP才能访问'
    def has_permission(self, request, view):
        # 把权限写入类里面
        if request.user.user_type != 1:
            return False
        return True  # 有权访问
class MyPermission1(object):
    def has_permission(self, request, view):
        # 把权限写入类里面
        if request.user.user_type == 3:
            return False
        return True  # 有权访问

如果写在全局,那么所有的都能用,如果不想用,字段换了就好了

# permission_classes = [MyPermission1, ]

有没有内置的权限呢?

有默认是return true

为了规范

from rest_framework.permissions import BasePermission
# 按照代码规范应该继承,内置的
class SVIPPermission(BasePermission):

别的权限,都是通过django写的

1568036241344

生产的环境,不可能是用默认的东西,都是自己去写(定制,而且级别也更高)

梳理:

  • 1 . restframework 写权限的时候,最好写到类中,放到他的组件中

​ 必须继承:BasePermission,必须实现: has_permission方法

  • 返回值

    return False  #无权访问
    return True     #有权访问
  • 局部:

    class UserInfoView(APIView):
        """订单相关业务(普通用户/vip)"""
        permission_classes = [MyPermission1, ] #加上这个
        def get(self, request, *args, **kwargs):
  • 全局:

    'DEFAULT_PERMISSION_CLASSES': ['app01.utils.permission.SVIPPermission'] 

下午:

1,2 登陆之后才能看, 什么用户(vip还是svip)

3,访问频率

限制: 比如1分钟多少次 6次

保存了一个访问记录的字典 = {身份证号:[12:10:10,12:10:09,12:10:08]}

# 12:10:10,12:10:09,12:10:08,12:10:07,12:10:06,12:10:05

12:50:10

[12:10:10,12:10:09,12:10:08,] 可以清除

12:10:11

[12:10:10,12:10:09,12:10:08,] 就是大于3次了,不能了

根据ip,可以记录

访问记录 = {用户IP:[....]} //但是ip可以换啊, 没办法, 匿名用户, 爬虫

注册用户, 可以限制, 所以现在手机号绑定了,但是用户名多了,也没法办 .

class VisitThrottle(object):
    def allow_request(self, request, view):
        # return True# 可以继续访问 # return False 表示访问频率太高,被限制
        return False
    def wait(self):
        pass

class AuthView(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes = [VisitThrottle,]
{
    "detail": "Request was throttled."
}

猜你喜欢

转载自www.cnblogs.com/Doner/p/11495862.html
DRF
1.5