一、APIView的基本使用
# drf:是一个第三方的app,只能在djagno上使用 # 安装了drf后,导入一个视图类APIView,所有后期要使用drf写视图类,都是继承APIView及其子类 # 现在通过一个继承View和继承APIView来写一个获取所有的图书的接口
View
class BookView(View): def get(self, request): print(type(request)) book_list = Book.objects.all() # book_list是queryset对象不能直接序列化,只能通过for循环一个个拼成列表套字典的形式 res_list = [] for book in book_list: res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish}) return JsonResponse(res_list,safe=False,json_dumps_params={'ensure_ascii':False}) # 在使用JsonResponse序列化出去
APIView
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.request import Request # 要加上drf的Response写这个接口 class BookView(APIView): # APIView继承自django的View 其实两个是一个View def get(self, request): book_list = Book.objects.all() # book_list是queryset对象不能直接序列化,只能通过for循环一个个拼成列表套字典的形式 res_list = [] for book in book_list: res_list.append({'name': book.name, 'price': book.price, 'publish': book.publish}) return Response(res_list) # Response可以直接序列化列表和字符串
二、APIView源码分析
# 首先APIView的路由也是按照下方这样写的 path('books/', views.Books.as_view()) '''然后我们可以点击as_view查看源码 然后因为我们自己写的试图类是没有这个方法的 所以我们要去继承的父类查找 那就是APIView ''' # APIView中是有as_view的方法的所以不用再去其他地方查找了 def as_view(cls, **initkwargs): # as_view中有调用了父类(View)的as_view方法 view = super().as_view(**initkwargs) # 然后返回了一个csrf装饰器 这样之后只要继承了APIView就可以不用在担心csrf校验了 return csrf_exempt(view) # 然后当路由匹配成功之后 因为APIView的as_view方法又调用了父类(View)的as_view方法 所以会执行View的as_view方法 而父类的as_view我们之前已经知道了其实就是返回了一个self.dispatch 方法 # 父类(View)的as_view def as_view(cls, **initkwargs): return self.dispatch(request, *args, **kwargs) # 这个self就是类本身 就是我们自己写的视图类
根据查找顺序当中途遇到一个方法的时候都是从最开始的本身开始查找然后在从父类查找..
所以我们就要再去我们自己写的试图类查找dispatch方法 没有 就要去APIView方法查找
def dispatch(self, request, *args, **kwargs): # 这个request是django原生的request的 # 然后initialize_request方法返回的是一个Request对象 所以接下来的request都是drf提供的Request的对象了 request = self.initialize_request(request, *args, **kwargs) self.request = request # 因为是视图类当做参数传入的 所以self就是我们自己写的视图类 就会变成了 视图类对象.request=request 新的request # 就是将我们试图类的request也变成了Request的对象 try: # 然后这里执行了三大认证: 认证、权限、频率 self.initial(request, *args, **kwargs) # 这里跟View里一样 都是判断请求来的时候 存不存在 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 # handler就是如果请求是get那么就是get 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
def initialize_request(self, request, *args, **kwargs): # 就是把传进来的request 变成drf提供的Request类的对象 return Request( # 返回Request的实例化对象 request, parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context )
1.总结
# 1.只要继承了APIView之后都没有csrf校验了 # 2.以后视图类中使用的request对象, 已经都变成了drf提供的Request类的对象了 # 3.在执行视图类方法之前 要先执行三大认证(认证、权限、频率) # 4.在执行三大认证和视图类的方法过程中只要报错, 都可以被异常捕获到
2.验证
#1 视图类中使用的request对象,已经变成了drf提供的Request类的对象了 # 我们可以在继承View的类中打印request的类型看一下 class BookView(View): def get(self, request): print(type(request)) # django.core.handlers.wsgi.WSGIRequest 这是原生django的request # 然后在继承APIView的类中打印request的类型 class BookView(APIView): def get(self, request): print(type(request)) # rest_framework.request.Request # 2.request已经不是原来的request了,还能像之前的方法一样用吗? 还是可以像之前的方法一样用 class BookView(APIView): def get(self, request): print(request.method) # get print(reuqest.path) # 路径 print(request.GET) # 原来的get参数 print(reuqest.POST) # 原来的post参数 # 向上面的参数还是能够使用 还是像之前一样的用法
三、Request类的源码分析
# 我们先要研究Request类的源码 rest_framework.request.Request 的入口其实就是导入这个模块就可以点击去查看 from rest_framework.request import Request # 在这个类实例化对象的时候 self._request = request 把原生django的request赋值给了self._request了 '''1.然后这个Request类中也有一个魔法方法__getattr__''' # 这个魔法方法只要 对象.属性 属性不存在的时候就会触发它的执行 def __getattr__(self, attr): # 如果取的属性不存在就会去原生django的request对象查找 try: return getattr(self._request, attr) # 然后通过该反射去原生django的request中查找 except AttributeError: return self.__getattribute__(attr) # 所以以后用所有的属性和方法 直接用即可(因为通过反射会去原生django的request中取) '''2.该类中还有一个data方法''' 该方法被property装饰了,变成了数据属性使用 ''' 以后body体中的数据都从这里取 之前是从request.POST中取 urlencoded,form-data:提交的数据在request.POST中 json格式提交的数据,在requets.POST中没有,它在request.body中 ''' # 现在无论什么格式都从request.data中取 其他: 取文件还是从request.FILES中取 '''3.该类中还有一个query_params方法''' @property def query_params(self): return self._request.GET # 该方法也被装饰成了属性 然后返回了_request.GET # 所以request.query_params 等同于 request._request.GET或 request.GET
验证
# 原生django的request.POST 只有urlencoded和form-data编码格式可以提交数据 而json格式数据在body体中 # 但是drf中只有data, data可以获取所有的编码格式的数据 # 而文件还是从request.FILES中获取
四、序列化组件简介
# 序列化就是drf提供的一个类, 然后我们继承它,写自己的类 # 可以序列化queryset对象或单个对象 # 就是当我们写好后端数据要返回给前端需要序列化才能给前端 所以drf给我们提供了一个类 # 我们之前写的获取所有图书的接口 -之前我们写的时候需要for循环,然后使用列表套字典的形式序列化给前端 # 现在有一个能够快速实现序列化的类:序列化类
五、序列化组件的使用
5.1 定义序列化类
# 首先我们可以在app下创建一个py文件在该py文件下写我们的序列化组件 from rest_framework import serializers class BookSerializer(serializers.Serializer): name = serializers.CharField() price = serializers.CharField() publish = serializers.CharField() # 哪个需要序列化就把哪个的字段给写上即可
5.2 在视图类中使用 序列化多条数据
# 查询全部书籍 class Books(APIView): def get(self, request): book_list = Book.objects.all() # instance 表示需要序列化的数据 many=True表示序列化多条(instance是queryset对象 如果要序列化多条数据 一定要传many=True) ser = BookSerializer(instance=book_list, many=True) return Response(ser.data)
5.3序列化单条数据
# 查询某个书籍 class BooksDetail(APIView): def get(self, request, pk): book_obj = Book.objects.filter(pk=pk).first() # instance还是放需要序列化的数据 如果是单条数据 不用传many=True ser = BookSerializer(instance=book_obj) return Response(ser.data)
六、反序列化(新增和修改)
# 新增和修改都是前端传进来的数据 需要反序列化和校验 而序列化类中有检验功能
6.1 新增
视图类
class Books(APIView): def post(self, request): # 从前端传过来的数据 要从request.data中提取 ser = BookSerializer(request.data) # 反序列化 if ser.is_valid(): # 这里就是判断传过来的数据需要校验 不过我们没有写数据校验 所以相当于没有校验 ser.save() # 这里如果直接写的话会报错 要重写create方法 return Response(ser.data) else: return Response(ser.errors) # 源码 def save() if self.instance is not None: self.instance = self.update(self.instance, validated_data) assert self.instance is not None, ( '`update()` did not return an object instance.' ) else: self.instance = self.create(validated_data) assert self.instance is not None, ( '`create()` did not return an object instance.' ) # 因为源码的save判断了instance是否为空如果为空 那么就调用了create方法 # 而源码的create什么都没写 直接报错 def create(self, validated_data): raise NotImplementedError('`create()` must be implemented.') # 所以我们要去我们自己写的序列化类中重写create方法
序列化类
class BookSerializer(serializers.Serializer): name = serializers.CharField() price = serializers.CharField() publish = serializers.CharField() def create(self, validated_data): # 只有上面的校验通过了才会执行 所以validated_data肯定有值 res = BookSerializer(**validated_data) return res # 还有返回出去 # 因为我们自己写的序列化类重写了create方法 所以在save在调用create方法的时候就会直接执行我们自己写的create方法
6.2 修改
视图类
class BooksDetail(APIView): def put(self, request, pk): book = Book.objects.filter(pk=pk).first() # 前端传过来的数据是从request.data中取 ser = BookSerializer(instance=book, data=request.data) if ser.is_valid(): ser.save() # 这里还是会报错 需要重写update方法 return Response(ser.data) else: return Response(ser.errors) # 刚刚源码中 如果instance有值的话save就会调用update方法 # 而源码的update方法也是直接报错什么都没有写 def update(self, instance, validated_data): raise NotImplementedError('`update()` must be implemented.') # 所以需要去自己写的序列化类重写update方法
序列化类
class BookSerializer(serializers.Serializer): name = serializers.CharField() 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() # 因为我们自己写的序列化类中写了update方法 所以save再调用update就会从我们自己写的序列化类中使用update方法
标签:APIView,self,request,instance,序列化,data,drf From: https://www.cnblogs.com/stephenwzh/p/16731985.html