1. 继承关系
图片来源https://blog.csdn.net/LHQ626/article/details/118400296
2.?GenericAPIView[通用视图类]
2.1. GenericAPIView介绍
a. 继承自APIVIew ,
b. 主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。
c. 通常在使用时,可搭配一个或多个Mixin扩展类。
2.2. 属性及方法介绍
属性
queryset?
指明表模型对象
serializer_class
指明视图使用的序列化器
?lookup_field = 'pk'
路由有名分组用的,这也就是有名分组,为什么只能填pk,
因为这里写死了,如果我们想要有名分组的变量,叫xxx
需要在外部视图配置一下
lookup_field = 'xxx'
filter_backends
# 默认内部查询的静态字段
filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
pagination_class??
默认内部分页用的静态字段
pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
方法
get_serializer_class(self)
外部使用
当出现一个视图类中调用多个序列化器时,
那么可以通过条件判断在get_serializer_class方法中,
通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。
# 当试图中使用多个序列化器类时,可以使用该方法来区分
class OrderView(CreateAPIView):
queryset = models.Order.objects.filter(is_deleted=False, is_show=True)
serializer_class = get_serializer_class
def get_serializer_class(self):
if self.request.method == 'GET':
return StudentModelSerializer1
return StudentModelSerializer2
?get_queryset(self)
一般内部使用,但是外部可以重写获得reuqest
返回视图使用的查询集,主要用来提供给Mixin扩展类使用,
是列表视图与详情视图获取数据的基础,默认返回`queryset`属性。
重写帮助视图拿到request,比如可以用于ListAPIView
class OrderDataView(ListAPIView):
"""查询属于与自己的订单"""
permission_classes = [IsAuthenticated, ]
serializer_class = OrderDataModelSerializer
def get_queryset(self):
queryset = models.Order.objects.filter(user=self.request.user, is_deleted=False)
return queryset
?get_object(self)
外部使用
返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。
在试图中可以调用该方法获取详情信息的模型类对象。
若详情访问的模型类对象不存在,会返回404.
# get_object()方法根据pk参数查找queryset中的数据对象
该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。
class BookDetailView(GenericAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
def get(self, request, pk):
book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
serializer = self.get_serializer(book)
return Response(serializer.data)
?get_serializer(self, *args, **kwargs)/get_serializer_context(self)
两个都是内部使用
get_serializer(self, *args, **kwargs)
其返回一个serializer_class
内部使用的,一般外部不用。
外部使用:self.get_serializer()()
调用封装request的方法,把request给封装进了context,
以后self.context.get('request'),就可以拿到request
def get_serializer(self, *args, **kwargs):
serializer_class = self.get_serializer_class()
kwargs.setdefault('context', self.get_serializer_context())
return serializer_class(*args, **kwargs)
# get_serializer_context(self)
# 封装request的方法
def get_serializer_context(self):
return {
'request': self.request,
'format': self.format_kwarg,
'view': self
}
get_serializer_class
内部使用
外部配置的serializer_class,被其进行相关的处理
def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
return self.serializer_class
filter_queryset(self, queryset)
# 内部使用
# 过滤用的,
def filter_queryset(self, queryset):
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(self.request, queryset, self)
return queryset
paginate_queryset(self, queryset)
# 内部使用
# 分页处理
def paginate_queryset(self, queryset):
if self.paginator is None:
return None
return self.paginator.paginate_queryset(queryset, self.request, view=self)
2.3.?基于GenericAPIView写的接口?
# views.py
class Book2View(GenericAPIView):
#queryset要传queryset对象,查询了所有的图书
# serializer_class使用哪个序列化类来序列化这堆数据
queryset=Book.objects
# queryset=Book.objects.all()
serializer_class = BookSerializer
def get(self,request):
book_list=self.get_queryset()
book_ser=self.get_serializer(book_list,many=True)
return Response(book_ser.data)
def post(self,request):
book_ser = self.get_serializer(data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response({'status':101,'msg':'校验失败'})
class Book2DetailView(GenericAPIView):
queryset = Book.objects
serializer_class = BookSerializer
def get(self, request,pk):
book = self.get_object()
book_ser = self.get_serializer(book)
return Response(book_ser.data)
def put(self, request,pk):
book = self.get_object()
book_ser = self.get_serializer(instance=book,data=request.data)
if book_ser.is_valid():
book_ser.save()
return Response(book_ser.data)
else:
return Response({'status': 101, 'msg': '校验失败'})
def delete(self,request,pk):
ret=self.get_object().delete()
return Response({'status': 100, 'msg': '删除成功'})
#url.py
# 使用GenericAPIView重写的
path('books2/', views.Book2View.as_view()),
re_path('books2/(?P<pk>\d+)', views.Book2DetailView.as_view()),
3. 5个视图扩展类mixins
3.1?mixins介绍
a. 提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,
b. 如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。
c. 这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。
3.2?mixins源码
CreateModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
DestroyModelMixin,
ListModelMixin,
class ListModelMixin:
"""
List a queryset.
"""
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
class RetrieveModelMixin:
"""
Retrieve a model instance.
"""
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
class UpdateModelMixin:
"""
Update a model instance.
"""
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response(serializer.data)
def perform_update(self, serializer):
serializer.save()
def partial_update(self, request, *args, **kwargs):
kwargs['partial'] = True
return self.update(request, *args, **kwargs)
class DestroyModelMixin:
"""
Destroy a model instance.
"""
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
def perform_destroy(self, instance):
instance.delete()
3.3 基于GenericAPIView和5个视图扩展类写的接口
from rest_framework.mixins import ListModelMixin,CreateModelMixin,UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin
# views.py
class Book3View(GenericAPIView,ListModelMixin,CreateModelMixin):
queryset=Book.objects
serializer_class = BookSerializer
def get(self,request):
return self.list(request)
def post(self,request):
return self.create(request)
class Book3DetailView(GenericAPIView,RetrieveModelMixin,DestroyModelMixin,UpdateModelMixin):
queryset = Book.objects
serializer_class = BookSerializer
def get(self, request,pk):
return self.retrieve(request,pk)
def put(self, request,pk):
return self.update(request,pk)
def delete(self,request,pk):
return self.destroy(request,pk)
# urls.py
# 使用GenericAPIView+5 个视图扩展类 重写的
path('books3/', views.Book3View.as_view()),
re_path('books3/(?P<pk>\d+)', views.Book3DetailView.as_view()),
4 GenericAPIView的视图子类
4.1 GenericAPIView的子类介绍
a. 视图子类,也叫通用视图子类。
b. 继承了GenericAPIView,以及Mixin,真正的实现了几行代码,完成一个视图
c. 其实就是帮你,return了视图中手动return的方法
1)CreateAPIView
提供 post 方法
继承自: GenericAPIView、CreateModelMixin
2)ListAPIView
提供 get 方法
继承自:GenericAPIView、ListModelMixin
3)RetrieveAPIView
提供 get 方法
继承自: GenericAPIView、RetrieveModelMixin
4)DestoryAPIView
提供 delete 方法
继承自:GenericAPIView、DestoryModelMixin
5)UpdateAPIView
提供 put 和 patch 方法
继承自:GenericAPIView、UpdateModelMixin
6)RetrieveUpdateAPIView
提供 get、put、patch方法
继承自: GenericAPIView、RetrieveModelMixin、UpdateModelMixin
7)RetrieveUpdateDestoryAPIView
提供 get、put、patch、delete方法
继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin
4.2?GenericAPIView的视图子类&Mixin书写接口
"""使用GenericAPIView的视图子类进一步简化开发api接口的代码"""
from rest_framework.generics import ListAPIView,CreateAPIView
class Students3GenericAPIView(ListAPIView,CreateAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
from rest_framework.generics import RetrieveAPIView,UpdateAPIView,DestroyAPIView
from rest_framework.generics import RetrieveUpdateDestroyAPIView # 结合了上面三个子类的功能
class Student3GenericAPIView(RetrieveUpdateDestroyAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
5.?视图集基类viewsets
5.1 源码分析ViewSetMixin
# 重写了as_view
# 核心代码(所以路由中只要配置了对应关系,比如{'get':'list'}),当get请求来,就会执行list方法
for method, action in actions.items():
#method:get
# action:list
handler = getattr(self, action)
#执行完上一句,handler就变成了list的内存地址
setattr(self, method, handler)
#执行完上一句 对象.get=list
#for循环执行完毕 对象.get:对着list 对象.post:对着create
5.2 继承ViewSetMixin的视图类
# views.py
from rest_framework.viewsets import ViewSetMixin
class Book6View(ViewSetMixin,APIView): #一定要放在APIVIew前
def get_all_book(self,request):
print("xxxx")
book_list = Boaok.objects.all()
book_ser = BookSerializer(book_list, many=True)
return Response(book_ser.data)
# urls.py
#继承ViewSetMixin的视图类,路由可以改写成这样
path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),
5.3?viewsets数量
class ViewSet(ViewSetMixin, views.APIView):
"""
The base ViewSet class does not provide any actions by default.
"""
pass
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
"""
The GenericViewSet class does not provide any actions by default,
but does include the base set of generic view behavior, such as
the `get_object` and `get_queryset` methods.
"""
pass
class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `list()` and `retrieve()` actions.
"""
pass
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
5.4 使用ModelViewSet快速编写5个接口
(看着玩就行,一般不用他,封装程度太高)
# 1. views.py ViewSetMixin,APIView
from rest_framework.viewsets import ViewSetMixin
class Book6View(ViewSetMixin,APIView): #一定要放在APIVIew前
def get_all_book(self,request):
print("xxxx")
book_list = Boaok.objects.all()
book_ser = BookSerializer(book_list, many=True)
return Response(book_ser.data)
# urls.py
#继承ViewSetMixin的视图类,路由可以改写成这样
path('books6/', views.Book6View.as_view(actions={'get': 'get_all_book'})),
"""2. ViewSet 使用视图集把上面的两个视图类组成一个视图类"""
from rest_framework.viewsets import ViewSet
class StudentViewSet(ViewSet):
def get_all(self,request):
"""获取所有学生信息"""
data_list = Student.objects.all()
serializer = StudentModelSerializer(instance=data_list, many=True)
return Response(serializer.data)
def add_student(self,request):
return Response({"message":"添加成功!"})
def get_one(self,request,pk):
"""获取一个学生信息"""
instance = Student.objects.get(pk=pk)
serializer = StudentModelSerializer(instance=instance)
return Response(serializer.data)
# 3. ViewSet,ListAPIView,CreateAPIView,RetrieveAPIView
"""发挥下ViewSet的作用"""
from rest_framework.viewsets import ViewSet
from rest_framework.generics import ListAPIView,CreateAPIView,RetrieveAPIView
class Student2ViewSet(ViewSet,ListAPIView,CreateAPIView,RetrieveAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def get_all(self,request):
"""获取所有学生信息"""
return self.list(request)
def add_student(self,request):
return self.create(request)
def get_one(self,request,pk):
"""获取一个学生信息"""
return self.retrieve(request)
# 4 GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin
class Student3ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
def get_all(self,request):
"""获取所有学生信息"""
return self.list(request)
def add_student(self,request):
return self.create(request)
def get_one(self,request,pk):
"""获取一个学生信息"""
return self.retrieve(request)
# 5 GenericViewSet,ListModelMixin,CreateModelMixin,
RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
"""简化上面的代码"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin
class Student4ViewSet(GenericViewSet,ListModelMixin,CreateModelMixin,RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
# 6. views.py ModelViewSet
from rest_framework.viewsets import ModelViewSet
class Book5View(ModelViewSet): #5个接口都有,但是路由有点问题
queryset = Book.objects
serializer_class = BookSerializer
# urls.py
# 使用ModelViewSet编写5个接口
path('books5/', views.Book5View.as_view(actions={'get':'list','post':'create'})), #当路径匹配,又是get请求,会执行Book5View的list方法
re_path('books5/(?P<pk>\d+)', views.Book5View.as_view(actions={'get':'retrieve','put':'update','delete':'destroy'})),
|