首先,APIView是Rest Framework提供的所有视图的基类,继承了Django的View

其次,APIView和View的不同在于:

  • 他们传入视图方法中的request对象不是同一个,APIView的是Request对象,View的是HttpResponse对象。
  • APIView返回的是Response对象,是符合前端Accept要求的格式
  • 在dispatch分发前会进行身份认证,权限检查,流量控制

五个接口实例:

  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. from app01.ser import BooksSerializers
  4. from app01.models import Books
  5. # 基于APIView
  6. class BooksView(APIView):
  7. # 查所有
  8. def get(self, request):
  9. books = Books.objects.all()
  10. books_ser = BooksSerializers(instance=books, many=True)
  11. return Response(books_ser.data)
  12. # 增加
  13. def post(self, request):
  14. books_ser = BooksSerializers(data=request.data)
  15. if books_ser.is_valid():
  16. books_ser.save()
  17. return Response(books_ser.data)
  18. class BookView(APIView):
  19. # 查单个
  20. def get(self, request, pk):
  21. print(pk, type(pk))
  22. book = Books.objects.filter(pk=pk).first()
  23. book_ser = BooksSerializers(instance=book)
  24. return Response(book_ser.data)
  25. # 修改
  26. def put(self, request, pk):
  27. book = Books.objects.filter(pk=pk).first()
  28. book_ser = BooksSerializers(instance=book, data=request.data)
  29. if book_ser.is_valid():
  30. book_ser.save()
  31. return Response(book_ser.data)
  32. else:
  33. return Response({'message': book_ser.errors})
  34. # 删除
  35. def delete(self, request, pk):
  36. Books.objects.filter(pk=pk).delete()
  37. return Response({'message': '删除成功'})
  38. # urls.py
  39. path('books/', views.BooksView.as_view()),
  40. re_path(r'^book/(?P<pk>\d+)/', views.BookView.as_view()),

首先,GenericAPIView继承了APIView,并增加了操作序列化器和数据库查询方法

并提供了两个属性和两个方法

queryset:指要传的queryset对象

get_queryset():返回queryset对象

serializer_class:指明视图使用的序列化器,也就是哪个序列化类来序列化这堆数据

get_serializer():返回序列化器类

get_object():返回视图所需的模型类数据对象

源码如下:

  1. # from rest_framework.generics import GenericAPIView
  2. class GenericAPIView(views.APIView):
  3. queryset = None # 指要传的queryset对象
  4. serializer_class = None # 指明视图使用的序列化器,也就是哪个序列化类来序列化这堆数据
  5. ......
  6. def get_queryset(self):
  7. ......
  8. queryset = self.queryset
  9. # 判断传入的queryset是不是QuerySet的对象
  10. if isinstance(queryset, QuerySet):
  11. queryset = queryset.all() # 是就加all()——>Book.objects.all()
  12. return queryset # 返回queryset对象
  13. def get_serializer(self, *args, **kwargs):
  14. serializer_class = self.get_serializer_class()
  15. # 向序列化器对象的context属性补充三个数据,
  16. # request,当前视图的请求对象
  17. # format,当前请求的类视图对象
  18. # view,当前请求期望返回的数据格式
  19. kwargs.setdefault('context', self.get_serializer_context())
  20. return serializer_class(*args, **kwargs) # 返回序列化器类

五个接口实例:

  1. from rest_framework.generics import GenericAPIView
  2. from rest_framework.response import Response
  3. from app01.ser import BooksSerializers
  4. from app01.models import Books
  5. # 基于GenericAPIView
  6. class BooksView(GenericAPIView):
  7. queryset = Books.objects
  8. serializer_class = BooksSerializers
  9. # 查所有
  10. def get(self, request):
  11. books = self.get_queryset() # 相当于Books.objects.all()
  12. books_ser = self.get_serializer(instance=books, many=True)
  13. return Response(books_ser.data)
  14. # 新增
  15. def post(self, request):
  16. books_ser = self.get_serializer(data=request.data)
  17. if books_ser.is_valid():
  18. books_ser.save()
  19. return Response(books_ser.data)
  20. class BookView(GenericAPIView):
  21. queryset = Books.objects
  22. serializer_class = BooksSerializers
  23. # 查单个
  24. def get(self, request, pk):
  25. book = self.get_object()
  26. book_ser = self.get_serializer(instance=book)
  27. return Response(book_ser.data)
  28. # 修改
  29. def put(self, request, pk):
  30. book = self.get_object()
  31. book_ser = self.get_serializer(instance=book, data=request.data)
  32. if book_ser.is_valid():
  33. book_ser.save()
  34. return Response(book_ser.data)
  35. else:
  36. return Response({'message': book_ser.errors})
  37. # 删除
  38. def delete(self, request, pk):
  39. self.get_object().delete()
  40. return Response({'message': '删除成功'})

因为之前代码的处理流程重复代码太多,所以可以使用相应的扩展类来减少编写的代码量。

而这五个扩展类需要搭配GenericAPIView父类,并且还要调用GenericAPIView提供的序列化器和数据查询方法。

列表视图扩展类(类似于查询所有),提供了快速获取所有列表的视图,并且该方法会对数据进行过滤和分页,成功返回200

源代码:

  1. class ListModelMixin:
  2. def list(self, request, *args, **kwargs):
  3. # 过滤
  4. queryset = self.filter_queryset(self.get_queryset())
  5. # 分页
  6. page = self.paginate_queryset(queryset)
  7. if page is not None:
  8. serializer = self.get_serializer(page, many=True)
  9. return self.get_paginated_response(serializer.data)
  10. # 序列化
  11. serializer = self.get_serializer(queryset, many=True)
  12. return Response(serializer.data) # 返回序列化后的数据

创建视图扩展类(创建数据),提供了快速创建资源的视图,成功返回201,失败400

原代码:

  1. class CreateModelMixin:
  2. # 创建模型实例
  3. def create(self, request, *args, **kwargs):
  4. # 获取序列化器
  5. serializer = self.get_serializer(data=request.data)
  6. # 验证
  7. serializer.is_valid(raise_exception=True)
  8. # 保存
  9. self.perform_create(serializer)
  10. headers = self.get_success_headers(serializer.data)
  11. return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
  12. # 保存方法
  13. def perform_create(self, serializer):
  14. serializer.save()
  15. def get_success_headers(self, data):
  16. try:
  17. return {'Location': str(data[api_settings.URL_FIELD_NAME])}
  18. except (TypeError, KeyError):
  19. return {}

详情视图扩展类(查询单个),返回一个存在的数据对象,成功返回201,失败404

原代码:

  1. class RetrieveModelMixin:
  2. def retrieve(self, request, *args, **kwargs):
  3. # 获取对象,并检查对象的权限
  4. instance = self.get_object()
  5. # 序列化
  6. serializer = self.get_serializer(instance)
  7. return Response(serializer.data)

更新视图扩展类(更新数据),快速更新一个存在的数据对象,也可实现局部更新 partial_update() 成功返回201,失败400

源代码

  1. class UpdateModelMixin:
  2. def update(self, request, *args, **kwargs):
  3. partial = kwargs.pop('partial', False)
  4. # 获取对象
  5. instance = self.get_object()
  6. # 序列化
  7. serializer = self.get_serializer(instance, data=request.data, partial=partial)
  8. # 校验
  9. serializer.is_valid(raise_exception=True)
  10. # 保存
  11. self.perform_update(serializer)
  12. if getattr(instance, '_prefetched_objects_cache', None):
  13. instance._prefetched_objects_cache = {}
  14. return Response(serializer.data)
  15. # 保存
  16. def perform_update(self, serializer):
  17. serializer.save()
  18. # 局部更新
  19. def partial_update(self, request, *args, **kwargs):
  20. kwargs['partial'] = True
  21. return self.update(request, *args, **kwargs)

删除视图扩展类(删除数据),快速删除一个存在的数据对象,成功返回204,不存在返回404。

源代码

  1. class DestroyModelMixin:
  2. def destroy(self, request, *args, **kwargs):
  3. # 获取对象
  4. instance = self.get_object()
  5. # 删除对象
  6. self.perform_destroy(instance)
  7. return Response(status=status.HTTP_204_NO_CONTENT)
  8. def perform_destroy(self, instance):
  9. instance.delete()
  1. from rest_framework.generics import GenericAPIView
  2. from app01.ser import BooksSerializers
  3. from app01.models import Books
  4. from rest_framework.mixins import ListModelMixin, CreateModelMixin
  5. from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
  6. # 基于GenericAPIView的五个视图扩展类
  7. class BooksView(GenericAPIView, ListModelMixin, CreateModelMixin):
  8. queryset = Books.objects
  9. serializer_class = BooksSerializers
  10. def get(self, request):
  11. return self.list(request)
  12. def post(self, request):
  13. return self.create(request)
  14. class BookView(GenericAPIView, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin):
  15. queryset = Books.objects
  16. serializer_class = BooksSerializers
  17. def get(self, request, pk):
  18. return self.retrieve(request)
  19. def put(self, request, pk):
  20. return self.update(request)
  21. def delete(self, request, pk):
  22. return self.destroy(request)

二话不说先来看其中一个源码!!!其他的子类都是一样的原理

源码

  1. # 首先它继承了CreateModelMixin创建视图扩展类
  2. class CreateAPIView(mixins.CreateModelMixin, GenericAPIView):
  3. # 并且它提供了post方法,那我们就不用在视图中写post方法了,这里直接写好了直接调用self.create
  4. # 只需要传入对象和序列化器就可以了
  5. def post(self, request, *args, **kwargs):
  6. return self.create(request, *args, **kwargs)

实例:

  1. from rest_framework.generics import ListAPIView, UpdateAPIView
  2. from rest_framework.generics import CreateAPIView, DestroyAPIView, RetrieveAPIView
  3. from app01.ser import BooksSerializers
  4. from app01.models import Books
  5. # 基于GenericAPIView的五个视图子类
  6. class BooksView(ListAPIView, UpdateAPIView): # 获取所有,新增一个
  7. queryset = Books.objects
  8. serializer_class = BooksSerializers
  9. # 获取一个,修改一个,删除一个
  10. class BookView(CreateAPIView, DestroyAPIView, RetrieveAPIView):
  11. queryset = Books.objects
  12. serializer_class = BooksSerializers

GenericAPIView的视图子类除了这五个还有四个,也就是这五个方法的其他组合:

  • ListCreateAPIView
    • 提供get、post方法,是 ListAPIView 和 UpdateAPIView 的组合
  • RetrieveDestroyAPIView
    • 提供get、delete方法,是 RetrieveAPIView 和 DestroyAPIView 的组合
  • RetrieveUpdateAPIView
    • 提供get、update方法,是 RetrieveAPIView 和 UpdateAPIView 的组合
  • RetrieveUpdateDestroyAPIView
    • 提供get、update、delete方法,是 RetrieveAPIView 、 UpdateAPIView 和 DestroyAPIView 的组合

首先它继承了 GenericViewSet,并且还有 ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

先来看一下它的使用:

  1. # views.py
  2. from rest_framework.viewsets import ModelViewSet
  3. from app01.ser import BooksSerializers
  4. from app01.models import Books
  5. class BooksView(ModelViewSet): # 五个接口都有
  6. queryset = Books.objects
  7. serializer_class = BooksSerializers
  8. # urls.py
  9. from django.contrib import admin
  10. from django.urls import path, re_path
  11. from app01 import views
  12. urlpatterns = [
  13. path('admin/', admin.site.urls),
  14. # 当路径匹配,又是get请求,会执行BooksView的list方法
  15. path('books/', views.BooksView.as_view({'get': 'list', 'post': 'create'})),
  16. re_path(r'^book/(?P<pk>\d+)/', views.BooksView.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'}))
  17. ]

由于 ModelViewSet 继承了 GenericViewSet ,并且 GenericViewSet 又继承了 ViewSetMixin,ViewSetMixin中又重写了 as_view 方法, 也就是说当路径匹配上了会执行这里重写的 as_view 方法。

分析: as_view 方法

  1. @classonlymethod
  2. def as_view(cls, actions=None, **initkwargs):
  3. ...
  4. def view(request, *args, **kwargs):
  5. self = cls(**initkwargs)
  6. # 核心代码,所有路由中只要配置了对应关系,比如{'get': 'list'},当get请求来,就会执行list方法
  7. for method, action in actions.items():
  8. # 遍历我们传入的对应关系
  9. # method = get
  10. # action = list
  11. # 并且通过反射获取list方法的内存地址
  12. handler = getattr(self, action) # handler已经是list的内存地址
  13. # 点拦截(对象.get = list)
  14. setattr(self, method, handler)
  15. # 当循环完毕之后,对象.get:对应list方法,对象.post:对应create方法
  16. ...
  17. # 后面照常继续
  18. return self.dispatch(request, *args, **kwargs)

由上面的分析可以得出,我们也可以直接继承 ViewSetMixin 写视图,如下:

  1. from rest_framework.viewsets import ViewSetMixin
  2. from rest_framework.response import Response
  3. from app01.ser import BooksSerializers
  4. from app01.models import Books
  5. class BooksView(ViewSetMixin, APIView):
  6. def get_all_books(self, request):
  7. book_list = Books.objects.all()
  8. book_ser = BooksSerializers(book_list, many=True)
  9. return Response(book_ser.data)
  10. # urls.py
  11. # 当匹配上了路由,又是get请求,就调用get_all_books方法
  12. path('books/', views.BooksView.as_view({'get': 'get_all_books'})),

版权声明:本文为XiaoYang-sir原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/XiaoYang-sir/p/14988276.html