内容概要
-
反序列化类校验部分源码解析
-
断言
-
drf-请求
-
drf-响应
-
视图组件介绍及两个视图基类
-
基于GenericAPIView+5个视图扩展类
反序列化类校验部分源码分析
反序列化类校验时机
# 反序列校验顺序
视图类中导入的序列化类对象 通过句点符点is_valid()方法后 开始进行校验
# serializer_obj = XXSerializer() 在视图类中产生序列化对象
所以我们应从serializer_obj.is_valid()方法中看看经过了什么步骤
我们先假设序列化类为
BookSerializer # 继承的是Serializer
我们去类中寻找is_vialid()方法
但是这个类中并没有该方法,我们就应该去BookSerializer继承的类中去找
所以到了Serializer类中寻找is_vialid()方法
但是Serializer类中也没有,那就继续在Serializer继承的类中去找
最终:我们可以在BaseSerializer中找到is_viald()方法
def is_valid(self, *, raise_exception=False):
assert hasattr(self, 'initial_data'), (
'Cannot call `.is_valid()` as no `data=` keyword argument was '
'passed when instantiating the serializer instance.'
)
# 判断self 有没有_vaildated_data属性,如果没有就赋值给它,现在self就是我们 !序列化产生的对象!因为我们是serializer_obj.is_viald()进入的
# 既然如此我们就需要看run_validation(self.initial_data)赋值了什么东西
#self序列化类的对象,属性中没有_validated_data,一定会走这句【核心】
if not hasattr(self, '_validated_data'):
try:
self._validated_data = self.run_validation(self.initial_data)
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
return not bool(self._errors)
我们需要进入run_validation(self.initial_data)中看一下,但是self是序列化对象,所以我们需要从头找起,而不是直接使用ctrl点进去,如果点进去我们找到的方法就是BaseSerializer继承的FIled字段中的run_validation方法
我们在Serializer类中找到了run_validation(self.initial_data)
def run_validation(self, data=empty):
# 字段自己的,validates方法
(is_empty_value, data) = self.validate_empty_values(data)
if is_empty_value:
return data
# 局部钩子----【局部钩子】
value = self.to_internal_value(data)
try:
self.run_validators(value)
# 全局钩子--》如果在BookSerializer中写了validate,优先走它,非常简单
value = self.validate(value)
assert value is not None, '.validate() should return the validated data'
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc))
return value
全局钩子
def validate(self, attrs):
return attrs
全局钩子很简单,就是我们正常编写的validate 全局钩子,我们使用全局钩子直接在序列化中重写方法即可
但是需要注意的是 必须要返回 attrs !
局部钩子
# 局部钩子 self.to_internal_value(data) ---》self是BookSerializer的对象,从根上找
def to_internal_value(self, data):
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
# fields写在序列化类中一个个字段类的对象
for field in fields:
# self BookSerializer的对象,反射validate_name
validate_method = getattr(self, 'validate_' + field.field_name, None)
try:
# 在执行BookSerializer类中的validate_name方法,传入了要校验的数据
validated_value = validate_method(validated_value)
except ValidationError as exc:
errors[field.field_name] = exc.detail
else:
set_value(ret, field.source_attrs, validated_value)
if errors:
raise ValidationError(errors)
return ret
断言
# 源码中大量使用try和断言
# 关键字assert ,有什么作用,断定你是xx,如果不是就抛异常
name = 'xiaoiming'
if name == 'xiaoiming':
print('对了')
else:
print('错了')
raise Exception('名字不为xiaoiming,不能继续走了')
assert name=='xiaoiming' # 断定是,如果不是,就抛异常
print('后续代码')
drf-请求
Request能够解析的前端传入的编码格式
# 需求: 接口只能够接收json格式数据,不能接收其他格式
方式1:
我们可以在继承自APIView及其子类的视图类中进行配置(局部配置)
# 总共有三个编码格式:
from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser,] # APIView中的类属性
方式2:
在配置文件中配置(影响所有接口!全局生效)
django中有默认配置,每个项目都有配置
drf也有默认配置,每个项目也有相应配置
就在django的配置文件中
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
# 'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
# 注释掉什么 就不可以通过 接收该编码格式
# 方式三:全局配了1个,某个视图类想要3个,怎么配?
-只需要在视图类,配置3个即可
-因为:先从视图类自身找,找不到,去项目的drf配置中找,再找不到,去drf默认的配置找
Request类中属性/方法
视图类方法中的request
class BookView(APIView)
# 继承了APIView 的视图类中request和 继承View 的视图类中 reuqest 不一样!
新 request 中
data ~ 数据为字典格式
__getattr__
query_params ~ request.GET
Resposne能够响应的编码格式
drf 是django的一个 app 所以我们需要进行注册
之前 drf没有报错是因为我们没有使用到 相应的功能
如果我们通过postman访问接口,和浏览器直接访问接口
数据会不一样
也就是说drf自动做了判断,如果不是浏览器访问接口就返回数据
浏览器访问接口的话就会返回相应格式
需求:
如果是浏览器访问接口,数据展示好看一些,如果是postman访问接口只要json数据
# 方式一:
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class BookView(APIView):
renderer_classes=[JSONRenderer,]
# 方式二:在项目配置文件中写(全局配置)
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}
# 方式三:使用顺序(一般就用内置的即可)
优先使用视图类中的配置,其次使用项目配置文件中的配置,最后使用内置的
Resposne的源码属性或方法
# drf 的Response 源码分析
导入Response
from rest_framework.respone import Response
# Response init可以传的参数
def __init__(self,
data=None,
status=None,
template_name=None,
headers=None,
exception=False,
content_type=None)
data: 之前我们编写的序列化类对象.data
可以是字典列表,字符串 序列化后返回给前端
status: http相应的状态码,默认为200
我们可以通过导入相应状态码进行修改
from rest_framework.status import HTTP_200_OK
Response('abc',status=status.HTTP_200_OK)
template_name:了解即可,修改响应模板的样子
headers:响应头,http响应的响应头
# 原生Django在相应头中携带数据
obj = HttpResponse('dddd')
obj['xxc'] = 'yyc'
return obj
content_type :响应编码格式,一般不动
视图组件介绍及两个视图基类
drf 视图 视图类
APIView 是 drf的基类 drf提供最顶层的类
# APIView跟之前的View区别
-传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
-视图方法可以返回REST framework的Response对象-
-任何APIException异常都会被捕获到,并且处理成合适的响应信息;
-在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制
APIView类-属性
APIVIew
-类属性:
renderer_classes # 响应格式
parser_classes #能够解析的请求格式
authentication_classes#认证类
throttle_classes#频率类
permission_classes#权限类
基于APIView+ModelSerializer+Resposne写5个接口
# urls 路由层
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('book/', views.BookView.as_view()),
path('book/<int:pk>/', views.BookDetailView.as_view()),
]
# views 视图层
from rest_framework.views import APIView
from app01 import models
from rest_framework.response import Response
from app01 import serializer
class BookView(APIView):
def get(self, request):
book_query_set = models.Book.objects.all()
serializer_obj = serializer.BookSerializer(instance=book_query_set,many=True)
return Response(serializer_obj.data)
def post(self,request):
serializer_obj = serializer.BookSerializer(data=request.data)
if serializer_obj.is_valid():
serializer_obj.save()
return Response({"msg":'新增成功'})
return Response({"msg":serializer_obj.errors})
class BookDetailView(APIView):
def get(self,request,pk):
book = models.Book.objects.filter(pk=pk).first()
serializer_obj = serializer.BookSerializer(instance=book)
return Response(serializer_obj.data)
def put(self,request,pk):
book = models.Book.objects.filter(pk=pk).first()
serializer_obj = serializer.BookSerializer(instance=book,data=request.data)
if serializer_obj.is_valid():
serializer_obj.save()
return Response({"msg": '修改成功'})
return Response({"msg": serializer_obj.errors})
def delete(self,request,pk):
models.Book.objects.filter(pk=pk).delete()
return Response()
# serializer 序列化类
from rest_framework import serializers
from app01 import models
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
fields = ['name', 'price','publish', 'authors', 'publish_detail', 'author_list'] # 序列化反序列化字段
extra_kwargs = {
"publish": {"write_only": True},
"authors": {"write_only": True},
# 'publish_detail': {'read_only': True}, # dict
# 'author_list': {'read_only': True}, # list
}
publish_detail = serializers.DictField(read_only=True)
author_list = serializers.ListField(read_only=True)
基于GenericAPIView+5个视图扩展类
视图类
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
ListModelMixin
# 基于GenericAPIView+5个视图扩展类写接口
class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request):
return self.list(request)
def post(self, request):
return self.create(request)
class BookDetailView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
序列化类
class BookSerializer(serializers.ModelSerializer):
# 跟表有关联
class Meta:
model = Book
fields = ['name', 'price', 'publish_detail', 'author_list', 'publish', 'authors']
extra_kwargs = {'name': {'max_length': 8},
'publish_detail': {'read_only': True},
'author_list': {'read_only': True},
'publish': {'write_only': True},
'authors': {'write_only': True},
}
路由
urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
标签:return,self,request,视图,组件,data,serializer,drf
From: https://www.cnblogs.com/ddsuifeng/p/17090520.html