APIView的使用、源码分析、Request类源码分析以及序列化组件介绍、基本使用、反序列化

APIView的基本使用

APIView是drf中views.py模块的一个类,它继承了django的View类,只能在django上使用

image-20220926144506115

安装了drf后,我们再写类视图的时候,可以使用drf的APIView:继承APIView以及子类

class Books(APIView):
    def get(self,request):
        return HttpResponse('')

使用View+JsonResponse写一个接口

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
from app01 import models
class Books(View):
    def get(self,request):
        res=models.Book.objects.all()
        book_list=[]
        for i in res:
            book_list.append({'title':i.title,'price':i.price,'publish':i.publish})
        return JsonResponse(book_list,safe=False,json_dumps_params={'ensure_ascii':False})
     
"""
注意:safe=False是非字典类型需要添加的参数,而json_dumps_params={'ensure_ascii':False})是JsonResponse继承于json,json_dumps_params的实参会打散作为json.dumps方法的关键字参数。
"""
image-20220926150749767

使用APIView+drf的Response写一个接口

当我们使用drf的时候,一定不能忘记在settings.py中注册rest_framework这个app

from rest_framework.response import Response
from rest_framework.views import APIView
from app01 import models
class Books(APIView):
    def get(self,request):
        res=models.Book.objects.all()
        book_list=[]
        for i in res:
            book_list.append({'title':i.title,'price':i.price,'publish':i.publish})
        return Response(book_list)
image-20220926150912986

APIView源码分析

当我们的视图类继承APIView后,执行流程就发生了变化,这个变化就是整个drf的执行流程

源码分析入口还是和之前的cbv一样,从路由层视图类的as_view开始,只不过这个as_view是APIView了,因为继承了APIView。

image-20220926152824159

由图可以看出:APIView的as_view方法会先调用父类的as_view,父类as_view里面有个闭包函数view,并返回了view,然后通过csrf_exempt取消了csrf的校验并返回。

image-20220926153524535

路由匹配成功之后会将类视图函数加括号执行,等于就是执行了view函数,这个是父类View中的view,父类中然后返回视图类中对象中的dispatch方法,根据对象方法的查找顺序,会从自身开始查找,APIView中有,就会执行APIView的dispatch方法

image-20220926160605177

APIView的dispatch方法中,首先通过initialize_request方法将原来View的request的对象变成了drf的request对象,然后执行了认证、频率、权限,之后就是对类中方法的反射处理执行,并且对认证、频率、权限、类中方法的反射进行了异常捕获,处理,返回到response对象中。

总结

  1. 只要继承了APIView都没有csrf的认证了
  2. 以后视图类中使用的request对象,已经变成了drf提供了Request类的对象了
  3. 执行视图类的方法之前,执行了3大认证(认证、权限、频率)
  4. 在执行三大认证和视图类的方法过程中只要报错,都会被捕获处理

Request类源码分析

视图类中使用的request对象,已经变成了drf提供的Request类的对象了

class Books(APIView):
    def get(self,request):
        print('drf的request:',request)
        print('原生的request:',request._request)
        res=models.Book.objects.all()
        book_list=[]
        for i in res:
            book_list.append({'title':i.title,'price':i.price,'publish':i.publish})
        return Response(book_list)
image-20220926164949630

request已经不是原来的request了,还能像原来的request一样使用吗?

image-20220926165316553

由图Request中的__getattr__可知,只要是旧的request有的属性或方法都可以使用。

print(request.GET)      # get提交的数据
print(request.method)   # 请求方法 
print(request.path)     # 路径
print(request.POST)     # post请求提交的数据
image-20220926165606410

Request的源码分析

__getattr__魔法方法

在rest_framework.request.Request类中查看,类中有个魔法方法:__getattr__:对象点属性,属性不存在的时候会触发它的执行

如果取的属性不存在会去原生django的request对象中取出来
def __getattr__(self, attr):
  """
  If an attribute does not exist on this instance, then we also attempt
  to proxy it to the underlying HttpRequest object.
          """
  try:
    return getattr(self._request, attr)  # self._request=request._request,就是原来的request
  except AttributeError:
    return self.__getattribute__(attr)

以后用的所有属性和方法,直接使用就可以,新的request会从原来的request中取

新的request内部有个老的request,就是

request._request   # 老的request

data方法

image-20220926171207715

data是一个方法,被装饰器property修饰了,变成了数据属性用。

以后从body体内提交的数据,都从这里取(request.POST)

  • urlencoded,form-data:提交的数据堵在request.POST中
  • json格式提交的数据,在request.POST中没有,它在request.body中

现在无论哪种格式,都从request.data中取

query_params方法

image-20220926172424567

get请求提交的参数,等同于request._request.GET或request.GET

其他

取文件也是从request.FILES中取,跟之前一样

验证

原生request.POST只有urlencoded和formdata格式提交的数据,json提交的数据在body中,拿出来自己处理,但是drf的request中只有data,data中可以取到任意编码提交的数据

image-20220926183813171

魔法方法

复习一下

序列化组件介绍

from rest_framework import serializers

序列化组件是drf提供的一个类,我们可以通过继承它,写自己的序列化类,用来序列化查询出来的queryset对象,可以帮我们简化很多代码,提供开发的效率。

新建一个serializer.py文件

from rest_framework import serializers
class BookSerializer(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.IntegerField()
    publish=serializers.CharField()

在视图类中序列化查询结果并返回

from rest_framework.response import Response
from rest_framework import views
from app01 import models
from app01 import serializer

class Books(views.APIView):
    def get(self,request,pk):
       res=models.Book.objects.filter(pk=pk).first()
       ser=serializer.BookSerializer(instance=res)

       return Response(ser.data)

序列化组件的基本使用

查看所有图书,并序列化返回

from rest_framework import serializers

class BookSerializer(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.IntegerField()
    publish=serializers.CharField()
from rest_framework.response import Response
from rest_framework import views
from app01 import models
from app01 import serializer

class Books(views.APIView):
    def get(self,request,pk):
       res=models.Book.objects.all()
       ser=serializer.BookSerializer(instance=res,many=True)
       return Response(ser.data)

反序列化

路由

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/',views.Books.as_view()),
    path('booksdetail/<int:pk>/',views.BooksDetail.as_view())
]

自定义序列化类

from rest_framework import serializers
from app01 import models
class BookSerializer(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.IntegerField()
    publish=serializers.CharField()
		
    # 重写create方法
    def create(self, validated_data):
      # validated_data表示校验过后的数据
        res=models.Book.objects.create(**validated_data)
        return res
    # 重写update方法
    def update(self, instance, validated_data):
        instance.title=validated_data.get('title')
        instance.price=validated_data.get('price')
        instance.publish=validated_data.get('publish')
        instance.save()
        return instance

视图类

from rest_framework.response import Response
from rest_framework import views
from app01 import models
from app01 import serializer

class Books(views.APIView):
    def get(self,request):
       res=models.Book.objects.all()
       ser=serializer.BookSerializer(instance=res,many=True)
       return Response(ser.data)
    def post(self,request):
      # 前端传递数据,从request.data取出来
        ser=serializer.BookSerializer(data=request.data)
        if ser.is_valid():  # 表示校验前端传入的数据,在序列化类中没有写规则,等于没校验
            ser.save()     # 如果自定义的序列化类中没有写create方法,这里会报错,调用BaseSerializer的save方法,判断了,如果instance有值执行update,meiyou值执行create
            return Response(ser.data)
        else:
            return Response(ser.errors)
# 单条数据
class BooksDetail(views.APIView):
    def get(self,request,pk):
        res=models.Book.objects.filter(pk=pk).first()
         # instance表示要修改的实例
        ser=serializer.BookSerializer(instance=res,data=request.data)
        return Response(ser.data)
    def put(self,request,pk):
        res=models.Book.objects.filter(pk=pk).first()
        # instance表示要修改的实例
        ser=serializer.BookSerializer(instance=res,data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)
image-20220926183707413

作业

  1. 继承apiview写5个接口

serializer.py

from rest_framework import serializers
from app01 import models
class BookSerializer(serializers.Serializer):
    title=serializers.CharField()
    price=serializers.IntegerField()
    publish=serializers.CharField()

    def create(self, validated_data):
        res=models.Book.objects.create(**validated_data)
        return res

    def update(self, instance, validated_data):
        instance.title=validated_data.get('title')
        instance.price=validated_data.get('price')
        instance.publish=validated_data.get('publish')
        instance.save()
        return self.instance

view.py

"""
查询所有
查询单条
修改id为1
增加1条
删除id为1
"""
# 序列化
class Books(views.APIView):
    def get(self,request):
        res=models.Book.objects.all()
        ser=serializer.BookSerializer(instance=res,many=True)
        return Response(ser.data)
    def post(self,request):
        ser=serializer.BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        else:
            return Response(ser.errors)


class BookDetail(views.APIView):
    def get(self,request,pk):
        res=models.Book.objects.filter(pk=pk).first()
        ser=serializer.BookSerializer(instance=res)
        return Response(ser.data)
    def put(self,request,pk):
        res=models.Book.objects.filter(pk=pk).first()
        ser=serializer.BookSerializer(instance=res,data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        return Response(ser.errors)
    def delete(self,request,pk):
        models.Book.objects.filter(pk=pk).delete()
        return Response('')

2.fbv写,写个装饰器,装饰在视图函数,只要一装饰,以后的request就可以使用,request.data,这个data无论是哪种编码格式,都有数据

class MyRequest(Request):
     @property
    def data(self):
        if self._request.POST:
            return {'post':self._request.POST}
        return {'get':self._request.GET,'body':self._request.body,'files':self._request.FILES}
def request_decorator(func_name):
    def inner(request,*args,**kwargs):
        request=MyRequest(request)
        print(request.data)
        res=func_name(request,*args,**kwargs)
        return res
    return inner
@request_decorator
def book_fbv(request):
    return JsonResponse({
        'data':request.GET
    })
posted @ 2022-09-26 21:44  荀飞  阅读(128)  评论(0编辑  收藏  举报