DRF的认证、权限、限流、序列化、反序列化
- 一、认证
- 二、权限
-
- [1. 直接使用,用户权限](#1. 直接使用,用户权限)
- 2.权限组件源码
- 三、序列化
-
- [1. 序列化](#1. 序列化)
-
- [1.1 自定义Serailizer类序列化](#1.1 自定义Serailizer类序列化)
- [1.2 在视图APIView中使用](#1.2 在视图APIView中使用)
- [1.3 自定义ModelSerializer类序列化](#1.3 自定义ModelSerializer类序列化)
- [1.4 不同格式的字段序列化](#1.4 不同格式的字段序列化)
-
-
- [1.4.1 自定义字段](#1.4.1 自定义字段)
- [1.4.2 日期自定义格式](#1.4.2 日期自定义格式)
- [1.4.3 自定义方法字段](#1.4.3 自定义方法字段)
- [1.4.4 嵌套,针对:一对多,多对多的情况](#1.4.4 嵌套,针对:一对多,多对多的情况)
- [1.4.5 继承](#1.4.5 继承)
-
- [2. 序列化-源码流程](#2. 序列化-源码流程)
- 四、反序列化
-
- [1. 反序列化流程](#1. 反序列化流程)
- [2. 数据校验](#2. 数据校验)
-
- 2.1数据校验是要在视图中校验的。但要在序列化类中写好校验规则。
- 2.2序列化类校验规则
-
- 2.2.1内置校验规则
- [2.2.2 正则校验规则](#2.2.2 正则校验规则)
- [2.2.3 钩子函数](#2.2.3 钩子函数)
- [2.24 ModelSerializer校验规则](#2.24 ModelSerializer校验规则)
- [2.2.5 字段属性(read_only,write_only)](#2.2.5 字段属性(read_only,write_only))
- 2.2.6对校验的总结
- 3.序列化字段与模型字段的总结
-
- [3.1 对于chioces与序列化、反序列化、模型字段名一致](#3.1 对于chioces与序列化、反序列化、模型字段名一致)
- [4. 数据校验-源码流程](#4. 数据校验-源码流程)
- 五、模型查询的常规操作
一、认证
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中设置)
pythonREST_FRAMEWORK = { "UNAUTHENTICATED_USER":None,#是让没有用户时为None,默认是AnyOne, "DEFAULT_AUTHENTICATION_CLASSES":["自定义认证类的位置"] } # 注:在配置全局时,不能写在视图类中。视图类还没有加载完。
在全局配置时,如果要让某个视图不进行认证,就在视图类中把authentication_classes=[]
-
注:
-
多个认证类
多个认证类是或的关系,但返回的值是None,前面的认证成功,后面的就不认证了。如果都不认证成功,一般最后一个为抛出异常类。
抛出异常类
pythonclass 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
-
权限组件的使用
- 局部使用(在视图中添加)
pythonfrom rest_framework.views import APIView class 视图类名(APIView): permission_classes = [权限类名1,权限类名2,权限类名3,....] #权限类名是一个且的关系,前面的是False后面的就不再执行了。
-
全局(setting.py)中
pythonREST_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. 数据校验-源码流程
五、模型查询的常规操作
- 对象.get_字段_display() #chioces显示后面的字段
- 对象.字段.字段#针对于一对多、多对多的情况
- filter(id__in=id列表)对于多个值的查询
- 对象添加值->对象.字段.set([id列表])#多对多的情况使用。