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()), ]