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中的闭包函数viewself.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()
        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