DRF的认证、权限、限流、序列化、反序列化

DRF的认证、权限、限流、序列化、反序列化

一、认证

1、直接用,用户授权

  • 实现方法

    • 编写 ->认证组件

    • 应用组件

  • 编写 ->认证组件

python 复制代码
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class 认证类(BaseAuthentication):
    def authenticate(self,request):
        1、 获取用户信息
        	1.1 可以从URL中获取,xx/xx/xx/?token=....
            	request.query_params(token) 来获取token值
            1.2 可以从请求头中获取
            	request.META.get("HTTP_AUTHORIZATION")
                # AUTHORIZATION传递过来的key
            1.3 可以从请求体中获取
            	request.data.get(token)
        2、校验用户信息的合法性
        3、返回结果
           - 3.1 正确,返回元组(用户信息,认证信息如token)
           - 3.2 错误,raise抛出错误信息
        		raise AuthenticationFailed({key:vaule})
            	#注:可以用字典提示错误
           - 3.3 错误返回None->多个认证类 [类1,类2,....]
        return user,auth
    def authenticate_header(self,request):
        return "token"
    #认证失败状态应该是401,如果authenticate_header不返回值,就是403

​ BaseAuthentication源码是:

python 复制代码
class BaseAuthentication:
    #注:只要在django中出现raise NotImplementedError(),就必须使用该方法,不然会出错!(重定义方法)。子类约束。
    def authenticate(self,request):
        raise NotImplementedError("必顺要写的函数。")
    def authenticate_header(self,request):
        pass
  • 应用组件
    • 局部
python 复制代码
from rest_framework.views import APIView
from rest_framework.response import Response
#在视图类中添加
class 视图类名(APIView):
    authentication_classes = [认证类1,认证类2,认证类3.....]
  • 全局(在setting中设置)

    python 复制代码
    REST_FRAMEWORK = {
        "UNAUTHENTICATED_USER":None,#是让没有用户时为None,默认是AnyOne,
        "DEFAULT_AUTHENTICATION_CLASSES":["自定义认证类的位置"]
    }
    # 注:在配置全局时,不能写在视图类中。视图类还没有加载完。

    在全局配置时,如果要让某个视图不进行认证,就在视图类中把authentication_classes=[]

  • 注:

    • 多个认证类

      多个认证类是或的关系,但返回的值是None,前面的认证成功,后面的就不认证了。如果都不认证成功,一般最后一个为抛出异常类。

      抛出异常类

      python 复制代码
      class NoAuthentictions(BaseAuthentication):
          def authenticate(self,request):
              raise AuthenticationFailed({key:vaule})
           def authenticate_header(self,request):
              return 'Token'

回顾

2、认证组件源码

3、第三方认证djangorestframework-simplejwt

djangorestframework-simplejwt教程及使用

二、权限

1. 直接使用,用户权限

  • 权限组件说明

  • 权限组件编写

python 复制代码
from rest_framework.permissions import BasePermission

class 权限类名(BasePermission):
    messge={.....}#权限失败是返回的错误信息
    def has_permission(self,request,view):
        1. 获取请求中的数据
        2. 校验
        3. 返回值
            3.1 返回True 表示校验通过
            3.2 返回False 表示校验没通过
     	return True | False
  • 权限组件的使用

    • 局部使用(在视图中添加)
    python 复制代码
    from rest_framework.views import APIView
    
    class 视图类名(APIView):
        permission_classes = [权限类名1,权限类名2,权限类名3,....]
        #权限类名是一个且的关系,前面的是False后面的就不再执行了。
    python 复制代码
    REST_FRAMEWORK = {
        "UNAUTHENTICATED_USER":None,#是让没有用户时为None,默认是AnyOne,
        "DEFAULT_AUTHENTICATION_CLASSES":["自定义认证类的位置"],
        "DEFAULT_PERMISSION_CLASSES":["自己定义的权限类位置"]#可以是一个列表
    }
    # 注:在配置全局时,不能写在视图类中。视图类还没有加载完。
  • 权限或组件的编写

    系统默认的是且关系,而不是或的关系,以下是或的关第编写

python 复制代码
#要在APIView中编写代码
from rest_framework.views import APIView

class 自定义或权限关系类名(APIView):
    def check_permission(self,request):
        permission_objects = self.get_permissions()
        for permission in permission_objects:
            if permission.has_permission(request,self):
                return
        else:
            self.permission_denied(
            	request,
                message=getattr(permission_objects[0],'message',None),
                code=getattr(permission_objects[0],'code',None)
            )
for...in...:
    ....
else:
    ....
#当循环完后,有返回False时,才执行else

在视图类中,继承自定义或权限关系类名

2.权限组件源码

三、序列化

1. 序列化

序列化,从数据库获取Query_Set或数据对像 ->JSON

序列化的流程

路由->视图->去数据库获取对象或QuerySet -> 序列化器的类转换成列表、字典、有序字典 -> JSON处理

1.1 自定义Serailizer类序列化

python 复制代码
from rest_framework import serializers
class 序列化类名(serializers.Serializer):
    字段 = serializers.类型()
    ...
    
 #字段要与数据库中的一致

1.2 在视图APIView中使用

python 复制代码
from rest_framework.views import APIView
frrom rest_framework.response import Response
class 视图类名(APIView):
    1. 获取数据库的数据instance
    2. 序列化数据
    ser = 序列化类名(instance = instance,many=True | False)#True是Query_Set,False是数据对像
    #ser.data才是真正的将数据对象或Query_set转化为JSON格式
    3.返回JSON数据
    return Response(ser.data)

关于序列化类many的说明

  • many=False是单个对象的序列化
  • many=True时是Query_set的序列化,它是加了下个for循环,再调用单个对象序列化

1.3 自定义ModelSerializer类序列化

由于序列化时,字段与模型中的字段是一样的,所以将其集中

python 复制代码
from from rest_framework.serializers import ModelSerializer
class 自定义ModelSerializer类名(ModelSerializer):
    class Meta:
        model = 模型类名
        fields = [字段类名列表] | "__all__"#所有字段都返回

1.4 不同格式的字段序列化

1.4.1 自定义字段

在modelserializer的字段自定制

python 复制代码
from from rest_framework.serializers import ModelSerialize
from from rest_framework.serializers
class 自定义ModelSerializer类名(ModelSerializer):
    字段 = serailizes.类型(source="数据库的字段")#自定义字段,要在field中添加自定义字段名
    class Meta:
        model = 模型类名
        fields = [字段类名列表] | "__all__"#所有字段都返回

注:

  • source是数据库的字段
  • source支持对象的访问,如obj.字段.外键字段名 | obj.get_字段_display#get_字段_display运行时会自动加上括号
  • 在fields中要添加自定义字段名,可以不与数据名一致

1.source对接的是数据库。2.支持orm对数据库的操作。3.带有函数的不用加括号。

1.4.2 日期自定义格式
python 复制代码
from from rest_framework.serializers import ModelSerialize
from from rest_framework.serializers 
class 自定义ModelSerializer类名(ModelSerializer):
    日期字段 = serailizes.DateTimeField(format="%y-%m-%d") #日期格式显式
    class Meta:
        model = 模型类名
        fields = [字段类名列表] | "__all__"#所有字段都返回
1.4.3 自定义方法字段
python 复制代码
from from rest_framework.serializers import ModelSerialize
from from rest_framework.serializers 
class 自定义ModelSerializer类名(ModelSerializer):
    自定义方法字段 = serailizes.SerializerMethodField()
    class Meta:
        model = 模型类名
        fields = [字段类名列表] | "__all__"#所有字段都返回
        
    def get_自定义方法字段(self,obj):
        obj是对象值
        retrun 序列化的值
1.4.4 嵌套,针对:一对多,多对多的情况
python 复制代码
from from rest_framework.serializers import ModelSerialize
from from rest_framework.serializers 

class 一对多类名(ModelSerializer):
    class Meta:
        model = 模型类名
        fields = [字段类名列表] | "__all__"#所有字段都返回

class 多对多类名(ModelSerializer):
    class Meta:
        model = 模型类名
        fields = [字段类名列表] | "__all__"#所有字段都返回
        
class 自定义ModelSerializer类名(ModelSerializer):
    一对多字段名 = 一对多类名()
    多对多字段名 = 多对多类名()
    class Meta:
        model = 模型类名
        fields = [字段类名列表]
1.4.5 继承
python 复制代码
from from rest_framework.serializers import ModelSerialize
from from rest_framework.serializers 

class 继承类名(ModelSerializer):
    class Meta:
        model = 模型类名
        fields = [字段类名列表] | "__all__"#所有字段都返回
        
class 自定义ModelSerializer类名(ModelSerializer,继承类名):
    class Meta:
        model = 模型类名
        fields = [字段类名列表,可以添加自定义类名中的字段]

2. 序列化-源码流程

四、反序列化

1. 反序列化流程

路由-> 视图-> request.data ->校验(序列化器的类)->操作(数据库db,序列化器的类)

2. 数据校验

2.1数据校验是要在视图中校验的。但要在序列化类中写好校验规则。

python 复制代码
from rest_framework.views import APIView
frrom rest_framework.response import Response
class 视图类名(APIView
    def post(self,request,*arg,**kwarg)
        1. 获取数据库的数据
        2. 数据校验
        	ser = 序列化类名(data = request.data)
            ser.is_valid()#返回的是True或False
        	业务编写
        		校验通过后,可以能完ser.validated_data获取校验后的数据,返回是OrderadDict数据集。
                校验失败后,可以能完ser.errors获取错误信息,返回字典{字段:[ErrorDetail(错误提示)]}
        3.返回JSON数据
        return Response(ser.data)
    
ser.is_valid(raise_exception=True)#成功可以利用值。抛出异常 raise ValidationError(self.errors)
注:不用判断,直接返回值,或返回错误值。

2.2序列化类校验规则

内置校验规则与正则校验规则

2.2.1内置校验规则

required = True | False 是否必须校验规则。

max_length = nu 最大长度

min_length = nu 最小长度

2.2.2 正则校验规则
python 复制代码
var = serializers.CharField(validators=[RegesValidator(正则表达式,messege = "错误提示语!"),])
2.2.3 钩子函数
python 复制代码
from rest_framework import serializer
from rest_framework import exceptions
#在序列化式子中编写
class 钩子函数类名(serilizers.Serializer):
    字段 = serializer.类型()
    ...
    def validate_字段名(self,value):
        业务逻辑
        #value是传过来的值
        raise exceptions.ValidationError("校验失败时,错误提示语!")
        return value#也可以改变相关的值,返回给ser.validated_data中相应字段值
    defm validate(self,attr):
        attr是ser.validated_data的值
        所有字段校验通过了,最后校验这个函数。
        raise excptions.ValidationError("全局钩子校验失败时提示语。")
        #返回为{"non_field_errors":[ErrorDetail(string='....',code='invalid')]}
        #api_setting.NON_FIELD_ERRORS_KEYF表示指定全局,错误提示语Key
        可以setting.py 中添加
        "NON_FIELD_ERRORS_KEYF":'字符串'
        return attr#也可以对attr中的字典数据进行操作
2.24 ModelSerializer校验规则
python 复制代码
from rest_framework import serializer
from rest_framework import exceptions
#在序列化式子中编写
class 钩子函数类名(serilizers.ModelSerializer):
    class Meta:
        model = 数据库名
        fields = [字段列表] | "__all__"
        extra_keargs = {
            字段:{"validators":[RegexValidator(正则,messegs:"错误提示语")]},
            字段:{内置规则}如:{"max_length":50},
            ...
        }

在ModelSerializer中model对应的是数据库的字段,但不会把django模型中的限定语句加到序列化类中来,这时我们要自己加。可以用extra_kwargs={

字段:{...}

...

}

ModelSerializer的主要功能:

  • 可以简化模型字段与序列化字段的编写。
  • 可以将校验通过的数据,直接保存到数据库中。ser.save()
  • ser.save()有两个小问题(字段少了,字段多了)
    • 字段少了,可以在ser.save(少了的字段=value,...)
    • 字段多了,可以用ser.validated_data.pop(字段名)删除多余的字段数据。注:用pop删除后会返回删除的值。也可以用del ser.validated_data.get(字段名),用del 不返回值。
    • 用ser.save()是要序列化validated_data中的字段名与模型中的必存字段要一致。
    • ser没有使用save()时,ser.validated_data中没有id,但保存后就有了id。所以ser.data就可以序列化取值了。
2.2.5 字段属性(read_only,write_only)
  • read_only=Ture表示只序列化,不反序列化。
  • write_only=True表示只反序列化,不序列化。
  • 注:不能同时使用read_only、write_only。
  • 对于嵌套类时,也可以用read_only、write_only。
2.2.6对校验的总结

3.序列化字段与模型字段的总结

  • 序列化与模型取值这二个是独立的过程,模型取出的值后,再与序列化对接。序列化依据模型取出的数来进行操作,得到想要的结果。
  • 序列化时每一个字段依据模型取出的值操作来得到想要的结果。字段要与模型字段为依据来操作,就与source有关。注:默认source与序列化字段一致,特别指定时,可以不一样。为了得到想要的值就拓展了以下方法:
    • source=模型取值操作的方法一样
    • 自定义方法字段 = serailizes.SerializerMethodField()->def get_自定义方法字段(self,value)->返回就是JSON想要的结果。(注:默认read_only=True)
    • 嵌套类->使用时要关联模型类字段如:source=关联模型类字段
  • 反序列化与模型存值这二个是独立的过程,先获得前端传来的数据request.data.再校验->校验的过程,其实就是将取到的值与自身的校验规则是否合法,如果合法相应字段再与模型实例化,注模型实例化可以少字段。这就带来两个问题,反序列化的字段多了或少了。多了、少了都不能存入数据库中。所以要注意以下三个方面:
    • 多了要删除,可以看前面的(ModelSerializer的主要功能)
    • 少了要添加,可以看前面的(ModelSerializer的主要功能)
    • 保证ser.validated_data与模型中必存字段一致。

其实反序列化------>数据校验------>数据存储与模型数据存储是两个过程。它们只用ser.save()连结起来了。

3.1 对于chioces与序列化、反序列化、模型字段名一致

python 复制代码
from collections import OrdereDict
from rest_framework.fields import SkipField
from rest_framework.relations import PKOnlyObject

class NbHookSerializer(object):
    def to_representation(self,instance):
        ret = OrderedDcit()
        fields = self._readable_fields
        
        for field in fields:
            if hasattr(self,"nb_%s"% field.field_name):
                value = getattr(self,'nb_%s'%field.field_name)(instance)
                ret[field.field_name] = value
            else:
                try:
                    attribute = field.get_attribute(instance)
                except SkipField:
                    continue
                check_for_none = attribute.pk if isinstance(attribute,PKOnlyObject) else attribute
                if check_for_none is None:
                    ret[field.field_name] = None
                else:
                    ret[field.field_name] = field.to_representation(attribute)
        return ret
            

使用时,可以用类的继承-在写序列化时使用。继承要注意,要写在先,因为类的继承优先级是先到后。

4. 数据校验-源码流程

五、模型查询的常规操作

  1. 对象.get_字段_display() #chioces显示后面的字段
  2. 对象.字段.字段#针对于一对多、多对多的情况
  3. filter(id__in=id列表)对于多个值的查询
  4. 对象添加值->对象.字段.set([id列表])#多对多的情况使用。
相关推荐
倔强青铜三2 天前
Django 6.0来袭!这些新特性,真的令人振奋!
人工智能·python·django
Java水解3 天前
Django实现接口token检测的实现方案
后端·django
飞Link3 天前
【Django】Django 调用外部 Python 程序的完整指南
后端·python·django·sqlite
码界奇点3 天前
基于Django与Vue.js的RBAC权限管理系统设计与实现
vue.js·python·车载系统·django·毕业设计·源代码管理
计算机学姐3 天前
基于Python的智能点餐系统【2026最新】
开发语言·vue.js·后端·python·mysql·django·flask
计算机学姐4 天前
基于Python的在线考试系统【2026最新】
开发语言·vue.js·后端·python·mysql·django·flask
码界奇点4 天前
基于Django REST framework与Vue的前后端分离后台管理系统设计与实现
vue.js·后端·python·django·毕业设计·源代码管理
Q_Q5110082854 天前
python+springboot+django/flask基于深度学习的音乐推荐系统
spring boot·python·django·flask·node.js·php
Q_Q5110082854 天前
python+springboot+django/flask基于深度学习的淘宝用户购物可视化与行为预测系统
spring boot·python·django·flask·node.js·php
Q_Q5110082854 天前
python+django/flask+vue基于spark的西南天气数据的分析与应用系统
spring boot·python·spark·django·flask·node.js