Django-rest-framework框架之APIView与序列化详解

今日内容概要

  • 基于APIView+Response写视图类
  • APIView的执行流程(源码分析)
  • Request类的源码分析
  • 验证不同编码格式提交数据(request.POST)
  • 序列化类的序列化的使用
  • 序列化类的反序列化

基于APIView+Response写视图类

1.APIView的基本使用

  • 首先明确drf是一个第三方的app,只能在django上使用;
  • 其次在安装了drf后,导入一个视图类APIView,所有后期要使用drf写视图类,都是继承APIView及其子类。

2.前戏之使用View+JsonResponse写视图类
views.py

from django.http import JsonResponse
from django.views import View
from .models import Book

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})  # 只能序列化字典和列表,

3.使用APIView+drf的Response写(不要忘了注册rest_framework这个app)
settings.py

INSTALLED_APPS = [
   'django.contrib.admin',
   'django.contrib.auth',
   'django.contrib.contenttypes',
   'django.contrib.sessions',
   'django.contrib.messages',
   'django.contrib.staticfiles',
   'app01.apps.App01Config',
   'rest_framework'  # 注册drf这个app
]

views.py

from .models import Book

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request

class BookView(APIView):  # APIView继承自django的View
   def get(self, request):
       # print(type(self.request))  # 新的request
       # print(type(request))
       print(request._request)
       print(type(request._request)) #django.core.handlers.wsgi.WSGIRequest

       # print(request.method)  # get
       # print(request.path)  # /books/
       # print(request.GET)  # 原来的get请求提交的参数
       # print(request.POST)  # 原来post请求提交的参数

       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)

APIView的执行流程(源码分析)

视图类继承APIView后,执行流程就发生了变化,这个变化就是整个的drf的执行流程。
1.一旦继承了APIView入口

  • 路由配置跟之前继承View是一样的------找视图类的as_view----【APIView的as_view】
    请添加图片描述
源码展示:
       @classmethod
       def as_view(cls, **initkwargs):
           # 又调用了父类(View)的as_view
           view = super().as_view(**initkwargs)
           '''
           # 从此以后,所有的请求都没有csrf的校验了
           # 在函数上加装饰器
           @csrf_exempt
           def index(request):
               pass
           本质等同于 index=csrf_exempt(index)
           '''
           return csrf_exempt(view)
  • 请求来了,路由匹配成功会执行View类的as_view类方法内的view闭包函数(但是没有了csrf认证)。
  • 真正的执行,执行self.dispatch-------->APIView的dispatch
    请添加图片描述
源码展示:
    def dispatch(self, request, *args, **kwargs):
       # 参数的request是原来的django原生的request
       # 下面的request,变成了drf提供的Request类的对象---》return 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   

2.总结

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

Request类源码分析

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

  • 原生django的request是这个类的对象;
    django.core.handlers.wsgi.WSGIRequest
  • drf的request是这个类的对象:rest_framework.request.Request

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

  • 用起来与之前一样!!!
       print(request.method)  # get
       print(request.path)  # /books/
       print(request.GET)   # 原来的get请求提交的参数
       print(request.POST)  # 原来post请求提交的参数

3.Request的源码分析:rest_framework.request.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内部有个老的request,就是request._request
  • data是个方法,被property装饰了,变成了数据属性;
    请添加图片描述
    (1)以后body体中提交的数据,都从这里取(request.POST);
    (2)urlencoded,form-data:提交的数据在request.POST中;
    (3)json格式提交的数据,在request.POST中没有,它在request.body中;
    (4)现在无论那种格式,都从request.data中取
  • query_params:get请求提交的参数,等同于request._request.GET 或 request.GET
    请添加图片描述
  • 其他:取文件也是从request.FILES中取,跟之前一样

4.补充

  • 验证:原生requets.POST 只有urlencoded和form-data格式提交的数据,json格式提交的数据在body中,拿出来自己处理,但是drf的request中有个data,data中可以取到任意编码提交的数据。
  • request.data:有时候是(urlencoded,form-data)QueryDict,有时候(json)是字典

序列化类的序列化的使用

1.序列化组件介绍
首先序列化组件是drf提供的一个类,我们继承它来写自己的类。
作用在于序列化qs或单个对象。

2.使用步骤之第一步
定义一个序列化类。

# 写序列化类,给book进行序列化
# from rest_framework.serializers import Serializer
from rest_framework import serializers


class BookSerializer(serializers.Serializer):
   # 要序列化字段,有很多字段类,字段类有很多字段属性
   name = serializers.CharField()
   price = serializers.CharField()
   publish = serializers.CharField()

3.使用步骤之第二步(查询多条数据)
使用序列化类,序列化多条数据。

# 基于APIView+Response+序列化类写接口
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from serializer import BookSerializer
class BookView(APIView):  # APIView继承自django的view
   def get(self,request):
       book_list = Book.objects.all()
       # instance表示要序列化的数据,many=True表示序列化多条(instance是qs对象,一定要传many=True)
       ser = BookSerializer(instance=book_list, many=True)
       return Response(ser.data)

4.使用步骤之第三步(查询单条数据)
使用序列化类,序列化单条数据。

# 使用序列化类,序列化单挑数据
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
from serializer import BookSerializer
class BookDetailView(APIView):
   def get(self, request, pk):
       book = Book.objects.filter(pk=pk).first()
       ser = BookSerializer(instance=book)
       return Response(ser.data)

反序列化

1.新增数据

  • 视图类
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.serializer import BookSerializer

class BookView(APIView):  # APIView继承自django的view
	    def post(self,request):
       # 前端传递数据,从request.data中取出来
       ser = BookSerializer(data=request.data)
       if ser.is_valid(): # 表示校验前端传入的数据,没有写校验规则,现在等于没校验
           ser.save()    # 在写东西,这里会报错(原因:调用save会触发BookSerializer的save方法,胖断了如果instance优质则执行update,没有值则执行create。所以这边应该在序列化类中重写create方法!!!)
           return Response(ser.data)
       else:
           return Response(ser.errors)
  • 序列化类(重写了create方法)
# 写序列化类,给book进行序列化
# from rest_framework.serializers import Serializer
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.Serializer):
   # 要序列化字段,有很多字段类,字段类有很多字段属性
   name = serializers.CharField()
   price = serializers.CharField()
   publish = serializers.CharField()


   # 重写create方法
   def create(self,validated_data):
       res = Book.objects.create(**validated_data)
       return res

2.修改数据

  • 视图类
# 基于APIView+Response+序列化类写接口
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response	
from app01.serializer import BookSerializer

class BookView(APIView):  # APIView继承自django的view
   def post(self,request):
       # 前端传递数据,从request.data中取出来
       ser = BookSerializer(data=request.data)
       if ser.is_valid(): # 表示校验前端传入的数据,没有写校验规则,现在等于没校验
           ser.save()    # 在写东西,这里会报错(原因:调用save会触发BookSerializer的save方法,胖断了如果instance优质则执行update,没有值则执行create。所以这边应该在序列化类中重写create方法!!!)
           return Response(ser.data)
       else:
           return Response(ser.errors)
  • 序列化类(重写update方法)
# 写序列化类,给book进行序列化
# from rest_framework.serializers import Serializer
from rest_framework import serializers
from .models import Book

   # 重写update方法
   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()
       return instance

3.删除数据

  • 视图类
# 基于APIView+Response+序列化类写接口
from .models import Book
from rest_framework.views import APIView
from rest_framework.response import Response	
from app01.serializer import BookSerializer

class BookView(APIView):  # APIView继承自django的view
   def delete(self,request,pk):
       Book.objects.filter(pk=pk).delete()
       return Response()
  • 序列化类
# 写序列化类,给book进行序列化
# from rest_framework.serializers import Serializer
from rest_framework import serializers
from .models import Book

class BookSerializer(serializers.Serializer):
   # 要序列化字段,有很多字段类,字段类有很多字段属性
   name = serializers.CharField()
   price = serializers.CharField()
   publish = serializers.CharField()

小练习:

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

from django.http import JsonResponse
def login_auth(func_name):
   def inner(request,*args,**kwargs):
       request = APIView().initialize_request(request)

       res = func_name(request,*args,**kwargs)

       return res
   return inner


@login_auth
def auter(request):
   print(request.data)
   return JsonResponse(requesr.data)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值