反序列化类校验部分源码解析、断言、drf之请求、drf之响应、视图组件介绍及两个视图基类、GenericAPIView、5个视图扩展类
反序列化类校验部分源码解析
视图类中的ser.is_valid(),就会执行校验 校验通过返回True 不通过返回Flase
is_valid()
入口:
'''
ser.is_valid()是序列化类的对象 就假设序列化类是假设序列化类是BookSerializer -- 找is_valid()
没有--去ModelSerializer里找
没有--去父类Serializer里找
没有--去父类BaseSerializer中找--找到了
'''
def is_valid(self, *, raise_exception=False):
if not hasattr(self, '_validated_data'):
#首次判断self里有没有_validated_data 没有直接走try
try:
self._validated_data = self.run_validation(self.initial_data)
#首次 self序列化类的对象 属性中没有_validation 一定会走这句【核心】走过就有了 以后再来不走
except ValidationError as exc:
self._validated_data = {}
self._errors = exc.detail
else:
self._errors = {}
if self._errors and raise_exception:
raise ValidationError(self.errors)
#如果raise_exception是True 就会抛异常 统一处理 返回信息
return not bool(self._errors)
self._validated_data = self.run_validation(self.initial_data)
#一定不要直接摁ctrl点进去
'''
这里的self是序列化类BookSerializer的对象
找run_validation切记不是直接ctrl点进去查看
要从自身开始找顺序是先在BookSerializer里找
没有--去父类 ModelSerializer里找
没有--去父类Serializer里找--找到了
而不是直接点进去 查看的是Field中的run_validation
''''
raise_exception=True 校验没通过会直接抛异常就不用if判断了
run_validation()
def run_validation(self, data=empty):
(is_empty_value, data) = self.validate_empty_values(data)
#字段自己的和validates方法
if is_empty_value:
return data
value = self.to_internal_value(data)
#局部钩子
try:
self.run_validators(value)
value = self.validate(value)
#全局钩子 --- 如果在BookSerializer中写了validate,优先走他
except (ValidationError, DjangoValidationError) as exc:
raise ValidationError(detail=as_serializer_error(exc) return value
#局部钩子 self.to_internal_value(data)
self是BookSerializer的对象,从根上找
def to_internal_value(self, data):
ret = OrderedDict()
errors = OrderedDict()
fields = self._writable_fields
for field in fields:
validate_method = getattr(self, 'validate_' + field.field_name, None)
#self BookSerializer的对象 反射validate_name
try:
validated_value = validate_method(validated_value)
#在执行BookSerializer类中的validate_name方法 传入了要校验的数据 validated_value就是name参数
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
断言
关键字 assert 有什么用? 断定你是不是xxx 不是就直接抛异常
if判断:
# name = 'lqz'
# if name == 'lqz':
# print('对了')
# else:
# # print('错了')
# raise Exception('名字不为lqz,不能继续走了')
断言:
assert name=='xxx'
print('后续代码')
判断是不是 是走后续代码
判断不是 抛异常
drf之请求
1.Request能够解析前的前端传入的编码格式
方式一:在继承自APIView及其子类的视图类中配置(局部配置)
总共有三个:from rest_framework.parsers import JSONParser,FormParser,MultiPartParser
class BookView(APIView):
parser_classes = [JSONParser,]
方式二:在配置文件中配置(影响所有 全局配置)
django有套默认配置 每个项目有个配置
drf有套默认配置 每个项目也有个默认配置
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': [
# 'rest_framework.parsers.JSONParser',
'rest_framework.parsers.FormParser',
# 'rest_framework.parsers.MultiPartParser',
],
}
想用哪个就打开哪一个
方式三:全局配了1个 某视图类想要3个
只需要在视图类配置三个即可
因为先从视图类自身找 找不到去项目的drf配置中找 再找不到就去drf默认的配置找
2.Request类有哪些属性的方法
data 在data里面获取数据
__getattr__ 反射出老的request.method
query_params 等于 request.GET
drf之响应
1.Response能够响应的编码格式
drf 是djngo的一个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',
],
}
#想用哪个方式就打开哪个方式
方式三:使用顺序(一般用内置的即可)
优先使用视图类中的配置 其次使用项目配置文件中的配置 最后使用内置的
2.Resposne的源码属性或方法
drf的源码分析:
from rest_framework.response import Response
视图类的方法返回时 return Respones 走他的__init__,__init__可以传哪些参数
Response init可以传的参数
def __init__(self,
data=None,
status=None,
template_name=None,
headers=None,
exception=False,
content_type=None)
data:
之前写的ser.data 可以是字典、列表或字符串 -- 序列化后返回给前端 -- 前端在响应体中看到的就是这里面的数据
status:
http响应状态码 默认是200 可以自己更改
#drf在status包下 把所有的http响应状态码都写了一边 是常量
#导入模块from rest_framework.status import HTTP_200_OK
#Response('dddd',status=status.HTTP_201_OK)
template_name:
修改响应模板的样子 BrowsableAPIRenderer浏览器的样子是定死的 可以自己定制
headers:
响应头 headers = {k:v}样式
djgno怎么在响应头中加东西
obj = HttpResponse('ddd')
obj['xxx']='yyy'
return obj
content_type:
响应编码格式 一般不动
#重点:data、status,headers
视图组件介绍及两个视图基类
APIView 和 View区别
1.传入视图类的是drf的request 不是djngo的request
2.以后用的都是新的request
3.全局异常捕获
4.三大认证
两个视图基类
APIView :
类属性: renderer_classes 响应格式
parser_classes 能够解析的请求格式
authentication_classes 认证类
throttle_classes 频率类
permission_classes 权限类
1.APIView+ModelSerializer+Resposne写5个接口
第一层:初级
model.py
from django.db import models
#图书表
class Books(models.Model):
name = models.CharField(max_length=32)
price = models.CharField(max_length=32)
publish = models.ForeignKey(to="Publish", on_delete=models.CASCADE)
authors = models.ManyToManyField(to="Author")
#定制写在外键所在的表下面
def publish_dict(self):
return {'name':self.publish.name,'add':self.publish.add}
def author_list(self):
l = []
for author in self.authors.all():
l.append({'name':author.name,'phone':author.phone})
return l
#出版社表
class Publish(models.Model):
name = models.CharField(max_length=32)
add = models.CharField(max_length=32)
#作者表
class Author(models.Model):
name = models.CharField(max_length=32)
phone = models.CharField(max_length=32)
gender = models.CharField(max_length=2)
url.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('books/',views.BooksView.as_view()),
path('books/<int:pk>/',views.BookView.as_view())
views.py
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.response import Response
# Create your views here.
from .models import Books
from .serialize import BookSerializers
#不需要筛选条件的视图类
class BooksView(APIView):
#获取所有图书信息
def get(self,request):
books = Books.objects.all()
ser = BookSerializers(instance=books,many=True)
return Response(ser.data)
#新增图书信息
def post(self,request):
ser = BookSerializers(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功'})
else:
return Response({'code':101,'msg':ser.errors})
#需要额外条件的视图类
class BookView(APIView):
#获取某一本图书信息
def get(self,request,pk):
books = Books.objects.filter(pk=pk).first()
ser = BookSerializers(instance=books)
return Response(ser.data)
#修改某一本图书信息
def put(self,request,pk):
books = Books.objects.filter(pk=pk).first()
ser = BookSerializers(instance=books,data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功','result':ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
#删除某一本图书信息
def delete(self,request,pk):
Books.objects.filter(pk=pk).first().delete()
return Response({'code': 100, 'msg': '删除成功'})
serialize.py
from rest_framework import serializers
from .models import Books
class BookSerializers(serializers.ModelSerializer):
class Meta:
model = Books
fields =['name','price','publish','authors','publish_dict','author_list']
extra_kwargs = {
'publish':{'write_only':True},
'authors':{'write_only':True},
}
#用了ModelSerializer继承了Serializers 大部分请求不用写create和update 底层直接写好了
基于GenericAPIView扩展类
属性:
queryset: 要序列化或者反序列化的表模型数据
serializer_class: 使用的序列化类
lookup_field: 查询单条的路由分组分出来的字段名
filter_backends: 过滤类的配置
pagination_class: 分页类的配置
方法:
get_queryset: 获取要序列化的对象
get_object: 获取要序列化的单个对象
get_serializer:获取序列化类
get_serializer_class:差不多 一般不调用它 重写他
filter_queryset: 过滤有关
第二层:中级
只优化了views.py
这样的好处是 以后不管写哪一个视图类 里面的代码都不用动了
只需要更改queryset = Books.objects.all()和 serializer_class = BookSerializers即可
class BooksView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self,request):
books = self.get_queryset() #可以用self.queryset拿到 但不要这样用 有一个方法 可扩展性更高 后期可以重写get_queryset
ser = self.get_serializer(instance=books,many=True) #同理 但后期重写写的是get_serializer_class 指定哪个序列化类来序列化
return Response(ser.data)
def post(self,request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response({'code':100,'msg':'新增成功'})
else:
return Response({'code':101,'msg':ser.errors})
class BookView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self,request,pk):
books = self.get_object() #获取某一条 源码中定义 lookup_field = 'pk' 所以获取的参数必须是pk 可以在全局中修改
ser = self.get_serializer(instance=books)
return Response(ser.data)
def put(self,request,pk):
books = self.get_object()
ser = self.get_serializer(instance=books,data=request.data)
if ser.is_valid():
ser.save()
return Response({'code': 100, 'msg': '修改成功','result':ser.data})
else:
return Response({'code': 101, 'msg': ser.errors})
def delete(self,request,pk):
self.get_object().delete()
return Response({'code': 100, 'msg': '删除成功'})
基于GenericAPIView+5个视图扩展类
5个视图扩展类
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, ListModelMixin
CreateModelMixin:新增 -- 方法 --create
UpdateModelMixin:修改 -- 方法 --update
DestroyModelMixin:删除 -- 方法 --destroy
RetrieveModelMixin:查询单个 -- 方法 --retrieve
ListModelMixin:查询多个 -- 方法 --list
只优化了views.py
class BooksView(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class BookView(GenericAPIView,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = Books.objects.all()
serializer_class = BookSerializers
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)