APIView执行流程、Request对象源码分析、序列化器介绍和快速使用、反序列化、反序列化的校验

APIView执行流程

1.APIView

drf只能在django上进行使用,安装了drf之后,导入一个视图类APIView(继承django的view),在后期使用drf写视图类 ,都是继承APIView及其子类
# 特点
1.继承APIView父类(Django中view的子类)
2.具有view的所有特征
3.提供了认证、授权、限流等功能

2.基于APIView+JsonResponse 写接口

models.py:
from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.CharField(max_length=32)
    publish = models.CharField(max_length=32)
# 1  基于APIView+JsonResponse 写接口
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)
  1. 基于APIView+Response 写接口

# 2  基于APIView+Response 写接口
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 Response(book_list)  # 列表或者字典可以序列化

image

4.APIView的执行流程

image

# 路由中的path('books/', views.BookView.as_view())---->执行views.BookView.as_view()(),现在的as_view是APIView的as_view
@classmethod
    def as_view(cls, **initkwargs):
        # 调用父类的as_view,父类是django原生的View
        # 把djagno原生View的as_view方法中的闭包函数view拿出来
        view = super().as_view(**initkwargs)
        # csrf_exempt排除所有的csrf认证,相当于所有方法上加了装饰器
        return csrf_exempt(view)
# 路由匹配成功,执行 csrf_exempt(view)(requets)--->View的as_view中的闭包函数view---》self.dispatch---->self是视图类的对象---》BookiView---》就是APIView的dispatch
def dispatch(self, request, *args, **kwargs):
        # 参数的request是原来的django原生的request
        # 下面的request,变成了drf提供的request类的对象
        request = self.initialize_request(request, *args, **kwargs)
        # self是视图类的对象,视图对象.request=request 新的request
        self.request = request
        
        try:
            # 执行了认证,频率,权限
            self.initial(request, *args, **kwargs)
            # 原来的View的dispatch的东西
            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
总结APIView的执行流程:
1.只有继承APIView都没有csrf的认证
2.包装了新的request,以后视图类中使用的request对象,已经变成drf提供的request类的对象
3.在执行视图类的方法之前,执行了3大认证(认证,权限,频率)
4.在执行三大认证和视图类的方法过程中只要报错,都会被捕获处理

Request对象源码分析

原生的django的request是这个类的对象:
django.core.handlers.wsgi.WSGIRequest  
drf的request是这个类的对象:
from rest_framework.request import Request
方法 __getattr__    对象.属性,属性不存在会触发它的执行
   在视图类的方法中,执行request.method ,新的request是没有method的,就触发了新的Request的__getattr__方法的执行
        def __getattr__(self, attr):
            # 如果取的属性不存在,会去原生的django的request对象中取出来
            try:
                # 反射:根据字符串获取属性或者方法,self.request是原来的request
                return getattr(self._request, attr)
            except AttributeError:
                return self.__getattribute__(attr)
以后用方法或者属性的时候,直接用通过反射从原来的request中取出来
request.query_params----->查询参数,reestful规范请求地址中带查询参数
request.FILES----->前端提交过来的数据,我们可以在这里提取
总结:
1.新的request取不到,就会去取老的__getattr__
2.request.data无论什么编码,什么请求方式,只要body中的数据,都可以在其中取出来
3.request.query_params就是原来的request._request.GET
4.上传的文件从request.FILES
魔法方法:
__str__  打印对象会调用
__init__  类()调用
__call__   对象()调用
__str__    打印对象会调用
__getattr__   对象.属性    当对象获取的属性不存在时,返回获取这个不存在的属性名

序列化器-Serializer介绍和快速使用

序列化器的作用:
1.序列化:序列化器会把模型对象转换成字典,经过response以后变成json字符串
2.反序列化:把客户端发送过来的数据,经过request以后变成字典,序列化器完成数据校验功能,然后把字典转成模型

1.序列化多条

serializer.py--BookSerializer类
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 序列化字段
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()
views.py--->BookView类
from .serializer import BookSerializer
class BookView(APIView):
    def get(self,request):
        books = Book.objects.all()
        # 使用序列化类来完成
        ser = BookSerializer(instance=books,many=True)
        # instance要序列化的对象是books queryset对象
        # many=True只要是queryset对象要传many=True,如果是单个对象就不用传
        return Response(ser.data)

2.序列化单条

视图类---》BookDetailView
class BookDetailView(APIView):
    def get(self,request,*args,**kwargs):
        books = Book.objects.filter(pk=kwargs.get('pk')).first()
        # 使用序列化类来完成
        ser = BookSerializer(instance=books,)
        # instance要序列化的对象是books queryset对象
        # many=True只要是queryset对象要传many=True,如果是单个对象就不用传
        return Response(ser.data)
序列化类
from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    # 序列化字段
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()
url
urlpatterns = [
    path('books/<int:pk>/', views.BookDetailView.as_view()),
]

反序列化

1.反序列化的新增

序列化类
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from .models import Book

class BookSerializer(serializers.Serializer):
    # 序列化字段
    name = serializers.CharField()
    price = serializers.CharField()
    publish = serializers.CharField()

    def create(self, validated_data):
        # 保存到数据库
        book = Book.objects.create(**validated_data)
        return book
视图类
from .serializer import BookSerializer
class BookView(APIView):

    def post(self,request):
        # 吧前端传入的数据给data参数
        ser = BookSerializer(data=request.data)
        # 校验数据
        if ser.is_valid():
            # 保存,调用ser.save,自动触发写的create,将数据保存起来
            ser.save()
            return Response({'code':100,'msg':'新增成功','result':ser.data})
        else:
            return Response({'code':101,'msg':ser.errors})

image

2.反序列化的修改

序列化类
class BookSerializer(serializers.Serializer):
    # 序列化某些字段,这里写要序列化的字典
    name = serializers.CharField()  # serializers下大致跟models下的类是对应的
    price = serializers.CharField()
    publish = serializers.CharField()

    def update(self, instance, validated_data):
        # instance 要修改的对象
        # validated_data 校验过后的数据
        instance.name = validated_data.get('name')
        instance.price = validated_data.get('price')
        instance.publish = validated_data.get('publish')
        instance.save()  # orm的单个对象,修改了单个对象的属性,只要调用对象.save,就能把修改保存到数据库

        return instance  
视图类
class BookDetailView(APIView):
    def put(self, request, pk):
        book = Book.objects.filter(pk=pk).first()
        # 反序列化保存 ---借助于序列化类
        ser = BookSerializer(data=request.data, instance=book)
        if ser.is_valid():
            ser.save()  # 由于没有重写update,所以这报错
            return Response({'code': 100, 'msg': '修改成功', 'result': ser.data})
        else:
            return Response({'code': 101, 'msg': ser.errors})

3.反序列化的删除

class BookDetailView(APIView):    
    def delete(self, requset, pk):
        Book.objects.filter(pk=pk).delete()
        return Response({'code': 100, 'msg': '删除成功'})

反序列化的校验

局部钩子与全局钩子
# 反序列化校验的局部钩子 ,名字不能以sb开头
    def validate_name(self,name):
        # 校验name是否合法
        if name.startswith('s'):
            raise ValidationError('错误')
        else:
            return name

 # 全局钩子
    def validate(self, attrs):
        if attrs.grt('name') == attrs.get('publish'):
            raise ValidationError('名字不能一致')
        else:
            return attrs