APIview执行流程、Request对象源码分析、序列化器介绍和快速使用
APIview执行流程
1.基于APIview+JsonResponse编写接口
之前基于django原生的View编写接口
drf为我们提供了一个类(APIView)以后使用drf写视图类都要继承这个类及其子类
APIViews本身就是继承了Django原生的View
class BookView(APIView):
def get(self, request):
books = Book.objects.all()
book_list = []
for book in books:
book_list.append({'name': book.name, 'price': book.price, 'publish': book.publish})
return JsonResponse(book_list, safe=False)
2.基于APIview+Response编写接口
class BookViews(APIView):
def get(self, request):
books = Books.objects.all()
book_list = []
for book in books:
book_list.append({"name": book.name, "price": book.price})
return Response(book_list) #字典和列表都可以序列化
3.APIView的执行流程
路由中写的: path('books/', views.BookView.as_view())
请求来了执行第二个参数 views.BookView.as_view()()
现在的as_view是APIView的as_view
APIView的as_view方法:view还是原生的view 但是以后再也没有csrf验证了
@classmethod
#调用父类的as_view 父类是django原生的view
def as_view(cls, **initkwargs):
#view就是把django原生View中的as_view方法中的闭包函数view拿出来了
view = super().as_view(**initkwargs)
#相当于在所有的方法上面加上了装饰器 以后所有的请求方式都不用csrf验证了
return csrf_exempt(view)
路由匹配成功 执行csrf_exempt(view)(request)
去view(view本质没变还是那个view)中的as_view中的闭包函数view找self.dispatch(request, *args, **kwargs)其中的self是BookView视图类的对象
视图类没有就去他的父类APIView的dispatch找:
def dispatch(self, request, *args, **kwargs):
#request是django原生的request 老的request
request = self.initialize_request(request, *args, **kwargs)
#把老的request包装成新的request 这个request是drf提供的Request类的对象
#这个request就是新的了
#self._request = request 这是老的 把老的request放到self变成新的request
self.request = request
#把新的request放到了BookView视图类里面
try:
#执行了三大认证【】使用的都是新的reuqest
self.initial(request, *args, **kwargs)
#跟cbv一摸一样
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)
#在执行三大认证和视图类的方法过程中 如果出现了异常 都能捕获 ---全局异常捕获
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
总结:
1.去除csrf认证
2.包装新的request
3.执行视图类的方法之前执行三大认证
4.在执行三大认证和视图类过程中出现异常 全局异常捕获
5.以后用的request都是新的request
Request对象源码分析
老的:django.core.handlers.wsgi.WSGIRequest
新的:from rest_framework.request import Request
新的 request._request就是老的
Request源码:
方法:__getattr__ 在视图类的方法中 执行request.method 新的Request是没有method的 就触发了新的Request的__getattr__方法的执行
def __getattr__(self, attr):
try:
#从老的request中反射出 想要获取的属性
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)
request.data 这是一个方法 包装成了属性
以后无论是什么请求 放在body中提交的数据 都从request.data中取 取出来就是字典 无论哪种格式
request.query_params 这是一个方法 包装成了属性
get请求携带的参数 以后都从这里面取
query_params:查询参数----restful规范中 请求地址中带过滤参数
qurey_params 和 request._request.GET一样
request.FILES 这是一个方法 包装成了属性
前端提交过来的文件从这里取
和原生的不一样 可以直接存
总结:
1.新的request用起来和老的一样 执行request.method 新的取不到 就去老的取 触发__getattr__ 反射获取
2.request.data 无论什么编码、请求 只要在body中就从这里取 结果是字典
3.request.query_params 就是request._request.GET
4.上传文件从request.FILES取
序列化器介绍和快速使用
在写接口时 需要序列化和反序列化 反序列化就需要做数据校验
drf提供了固定写法 按照固定写法写就能完成以上条件
提供了两个类:SerializerModelSerializer
只需要写自己的类 继承drf提供的序列化类 使用其中的某些方法 即可
使用APIView+序列化类+Response完成接口编写
1.序列化类基本使用 序列化多条
serializer.py:
建立serializer.py文件在里面编写序列化类
from rest_framework import serializers
class BookSerializers(serializers.Serializer):
name = serializers.CharField()
#序列化的字段 这里写要序列化的字典
price = serializers.CharField()
views.py
class BookView(APIView):
def ger(self,request):
books = Books.objects.all()
ser=BookSerializer(instance=books,many=True)
#instance要序列化的数据books many=True 标识可以序列化多条
return Response(ser.data)
#无论字典还是列表都可以被序列化
2.序列化类基本使用 序列化单条
serializer.py:没变 还是一样的
建立serializer.py文件在里面编写序列化类
from rest_framework import serializers
class BookSerializers(serializers.Serializer):
name = serializers.CharField()
#序列化的字段 这里写要序列化的字典
price = serializers.CharField()
views.py
class BookView(APIView):
def ger(self,request,pk):
books = Books.objects.filter(pk=pk).first()
ser=BookSerializer(instance=books)
#instance要序列化的数据books many=True 标识可以序列化多条
return Response(ser.data)
#无论字典还是列表都可以被序列化
反序列化
1.反序列化的新增
serializer.py:
from .models import Books
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
name = serializers.CharField()
#序列化的字段 这里写要序列化的字典
price = serializers.CharField()
def create(self, validated_data):
#保存
#validated_data检验过后的数据{name price}
#保存到数据库
books = Books.objects.create(**validated_data)
return books
views.py:
class BooksView(APIView):
def post(self,request):
#前端提交的要保存的数据 -- 检验数据 -- 存进数据库
ser=BookSerializer(data=request.data)
#把前端传入的要保存的数据 给data参数
#检验数据
if ser.is_valid():
#保存 -- 需要自己写 要在系列化类BookSerializer中写create方法
ser.save() #调用ser.save()自动触发create 保存起来
return Response({'code':100,'msg':'新增成功','result':ser.data})
else:
return Response({'code':101,'msg':ser.errors})
2.反序列化修改
serializer.py:
def update(self, instance, validated_data):
#instance 要修改的对象
#validated_data 校验过后的对象
instance.name = validated_data.get('name')
instance.price = validated_data.get('price')
instance.save()
return instance
views.py:
class BookUpDate(APIView):
def put(self,request,pk):
books = Books.objects.filter(pk=pk).first()
#反序列化保存---借助于序列化类
ser = BookSerializer(data=request.data,instance=books)
if ser.is_valid():
ser.save() #写update方法
return Response({'code':100,'msg':'修改成功','result':ser.data})
else:
return Response({'code':101,'msg':ser.errors})
3.删除
views.py:
class BookDelete(APIView):
def delete(self,request,pk):
Books.objects.filter(pk=pk).first().delete()
return Response({'code':100,'msg':'删除成功'})
反序列化校验
序列化类反序列化类 数据校验功能 -- 类比form组件
局部钩子
全局钩子
局部钩子:
def validate_name(self,name):
if name == 'xxx':
raise ValidationError('NAME XXX IS ERROR')
else:
return name
全局钩子:
def validate(self,attrs):
if attrs.get('name') == attrs.get('price'):
raise ValidationError('A NAME DOES EQUAL A PRICE')
else:
return attrs