CBV源码分析;drf之APIView执行流程分析;drf之Request对象;序列化组件之Serializer的使用 # day66

CBV源码分析

# 我们在路由中写了 IndexView.as_view()---->实际上放了一个函数内存地址,源码是---》实际上是view的内存地址
    @classonlymethod
    def view(request, *args, **kwargs):
        return self.dispatch(request, *args, **kwargs)
    return view
# 当请求来了,跟路由匹配成功,就会执行view(request)
# 内部执行了self.dispatch(request, *args, **kwargs)
    def dispatch(self, request, *args, **kwargs):
        # 'get'  in  列表
        if request.method.lower() in self.http_method_names:
            # 通过反射去对象中拿get方法
            # handler就是get这个方法
            handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
        else:
            handler = self.http_method_not_allowed
        return handler(request, *args, **kwargs)
    
# 最终执行了handler(request, *args, **kwargs)
    -如果是get请求,相当于执行了视图类中的get方法

 

 

drf之APIView执行流程分析

class BookView(APIView):
    def get(self, request):
        book_list = Books.objects.all()
        l = []
        for book in book_list:
            l.append({'name': book.name, 'price': book.price})
        # return JsonResponse(l, safe=False)  # django中的JsonResponse传字典可以,要想传列表必须在列表后加上safe=False
        return Response(l)    # drf的response

 

# 请求来了,会执行views.BookView.as_view()(request)---->触发APIView的as_view
    @classmethod
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs) # 调用了View的as_view
        return csrf_exempt(view) # 去掉了csrf的认证,跟原来加装饰器一样
# 假设get请求来了,执行view()--最重要的-->self.dispatch()--》APIView的
    def dispatch(self, request, *args, **kwargs):
        # 把原来的request对象,包装成了新的request对象,是drf的request
        request = self.initialize_request(request, *args, **kwargs)
        try:
            # 执行了三大认证:认证,权限,频率
            self.initial(request, *args, **kwargs)
            # 跟原来一模一样
            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)
        return self.response
    
    
# 重点:
    apiview:干了三件事
        -把老的request对象包装成了新的request对象
            -通过APIView的initialize_request,包装的
            -以后再在视图类中用的request对象,都是新的
        -在执行视图类中的方法之前,执行了三大认证
            self.perform_authentication(request)
            self.check_permissions(request)
            self.check_throttles(request)
        -处理全局异常
        
        
    只要继承了APIView,以后用的request对象,就是drf的request对象了
    在执行视图类的方法之前,会先执行三大认证,如果有异常,会被捕获并处理

 

 

3 drf之Request对象

# from rest_framework.request import Request
# 重点
    -老的django的request在drf的request._request中
    -新的request用起来跟原来一模一样用,没有一点区别
        -对象.属性,会触发类的 __getattr__方法
        -重写了__getattr__
        return getattr(self._request, attr)
    -新的request多个一个data属性--》所有post提交的数据,都放在它中
    
   
    
# 补充:魔法方法
    -类中,某种特定条件就会触发它执行的方法
    -__init__, __str__
    
    
# __getattr__

 

 

 

4 序列化组件之Serializer的使用

from django.shortcuts import render, HttpResponse

# Create your views here.

from django.views import View

class IndexView(View):
    def get(self, request):
        return HttpResponse('OK')

from rest_framework.views import APIView
from rest_framework.response import Response
from django.http import JsonResponse
# from app01.models import Books  # 绝对导入
from .models import Books   # 相对导入

# class BookView(APIView):
#     def get(self, request):
#         book_list = Books.objects.all()
#         l = []
#         for book in book_list:
#             l.append({'name': book.name, 'price': book.price})
#         # return JsonResponse(l, safe=False)  # django中的JsonResponse传字典可以,要想传列表必须在列表后加上safe=False
#         return Response(l)    # drf的response


# 借助序列化类实现序列化
from .serializer import BookSerializer

class BookView(APIView):
    def get(self, request):
        book_list = Books.objects.all()
        # instance=book_list    要序列化这个queryset对象
        # many=True     因为对象是多条,它是queryset对象,必须用many=True。如果queryset对象是单条数据可以忽略不写
        ser = BookSerializer(instance=book_list, many=True)
        return Response(ser.data)    # drf的response

    def post(self, request):
        # 反序列化
        ser = BookSerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response('保存成功')
        else:
            return Response('出错了')

# 获取单个图书

class BookDetailView(APIView):
    def get(self, request, *args, **kwargs):
        print(kwargs['pk'])
        pk = kwargs['pk']
        book = Books.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book)
        return Response(ser.data)  # drf的response   # 序列化单条

    def put(self, request, pk):
        book = Books.objects.filter(pk=pk).first()
        ser = BookSerializer(instance=book, data=request.data)
        if ser.is_valid():
            ser.save()
            return Response('修改成功')
        else:
            return Response('修改失败')


        return Response(ser.data)

    def delete(self, request, *args, **kwargs):
        pk = kwargs['pk']
        Books.objects.filter(pk=pk).delete()

        return Response('删除成功')

 

# from rest_framework.serializers import Serializer
from .models import Books
from rest_framework import serializers
class BookSerializer(serializers.Serializer):
    # 写要序列化的字段
    id = serializers.IntegerField()
    name = serializers.CharField()
    price = serializers.IntegerField()

    # 重写create方法

    def create(self, validated_data):
        book = Books.objects.create(**validated_data)
        return book


    # 重写update
    def update(self, instance, validated_data):
        instance.name = validated_data['name']
        instance.price = validated_data['price']
        instance.save()
        return instance
from django.contrib import admin
from django.urls import path
from app01.views import IndexView
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', IndexView.as_view()),
    # IndexView.as_view() 执行完一定是函数的内存地址
    path('books/', views.BookView.as_view()),
    # django 2.x版本中的re_path相当于django 1.x中的url
    # django 2.x中支持转换器的使用
    # str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
    # int,匹配正整数,包含0。
    path('books/<int:pk>', views.BookDetailView.as_view()),
]

 

上一篇:直观对比django与DRF


下一篇:drf框架的学习