DjangoRESTframework(八)-9个视图子类的详细使用
使用视图集的原因:
针对9个视图子类这种写法写法虽然已经省略了http请求,但是在开发通用5个api接口时,还是会出现需要2个类来实现5个接口的情况。如下
class _ListCreateApiView(ListCreateAPIView):
serializer_class = BookSerializer
queryset = BookInfo.objects
class _RetrieveUpdateDestoryAPIView(RetrieveUpdateDestroyAPIView):
serializer_class = BookSerializer
queryset = BookInfo.objects
这主要的原因是2点:
1)获取多条数据与获取一条数据的http请求重复了。在django中依赖于请求方法来响应不同的http请求
2)部分接口需要pk值作为url地址
drf为了解决上面的2个问题,提供了视图集和路由集。视图集就可以帮我们实现一个视图类响应多种重复的http请求。路由集就可以帮我们实现自动根据不同的视图方法来生成不同参数的路由地址。
一、ViewSet
rest_framework.viewset.ViewSet
继承自APIView
与ViewSetMixin
,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典{“http请求”:“视图方法”}的映射处理工作,如{'get':'list'},
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
class ViewSet(ViewSetMixin, views.APIView):
"""
The base ViewSet class does not provide any actions by default.
"""
pass
1、编写视图
class ViewSetView(ViewSet):
def get_books_list(self, request):
"""获取所有图书模型对象的数据"""
books = BookInfo.objects.all()
ser = BookSerializer(instance=books, many=True)
return Response(data=ser.data, status=status.HTTP_200_OK)
def create_book(self, request):
"""创建图书模型对象"""
data = request.data
ser = BookSerializer(data=data)
if ser.is_valid() is False:
return Response(ser.errors)
ser.save()
return Response(data=ser.data)
def get_book_info(self, request, pk):
"""获取单一图书模型对象的数据"""
try:
book = BookInfo.objects.get(id=pk)
except BookInfo.DoesNotExist:
return Response(data='图书不存在')
ser = BookSerializer(instance=book)
Response(data=ser.data)
def delete_book(self, request, pk):
"""删除图书"""
try:
BookInfo.objects.get(id=pk).delete()
except BookInfo.DoesNotExist:
return Response(data='图书不存在')
return Response(data='删除成功')
def update_book(self, request, pk):
"""更新图书"""
data = request.data
book = BookInfo.objects.get(id=pk)
ser = BookSerializer(instance=book, data=data)
if ser.is_valid() is False:
return Response(ser.errors)
ser.save()
return Response(data=ser.data)
2、定义路由
urlpatterns = [
# --------------------ViewSet-----------------------------------------
path('demo/books/', ViewSetView.as_view({
'get': 'get_boos_list',
'post': 'create_book'
})),
re_path(r'^demo/books/(?P<pk>\d+)/$', ViewSetView.as_view({
"get": 'get_book_info',
'delete': 'delete_book',
'put': 'update_book'
})),
]
3、测试
二、GenericViewSet
继承自GenericAPIView和ViewSetMixin,作用让视图集的视图代码变得更加通用,抽离独特代码作为视图类的属性。
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
1、编写视图
class GenericViewSetView(GenericViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookSerializer
def list(self, request):
"""获取所有数据"""
# 1. 从数据库中读取模型列表信息
queryset = self.get_queryset() # GenericAPIView提供的get_queryset
# 2. 序列化
serializer = self.get_serializer(instance=queryset, many=True)
# 3. 转换数据并返回给客户端
return Response(serializer.data)
def create(self, request):
"""添加一个数据"""
# 1. 获取客户端提交的数据,实例化序列化器,获取序列化对象
serializer = self.get_serializer(data=request.data)
# 2. 反序列化[验证数据、保存数据到数据库]
serializer.is_valid(raise_exception=True)
serializer.save()
# 3. 返回新增的模型数据给客户单
return Response(serializer.data, status=status.HTTP_201_CREATED)
def retrieve(self, request, pk):
"""获取一个数据"""
# 1. 使用pk作为条件获取模型对象
instance = self.get_object()
# 2.序列化
serializer = self.get_serializer(instance=instance)
# 3. 返回结果
return Response(serializer.data)
def update(self, request, pk):
"""更新一个数据"""
# 1. 使用pk作为条件获取模型对象
instance = self.get_object()
# 2. 获取客户端提交的数据
serializer = self.get_serializer(instance=instance, data=request.data)
# 3. 反序列化[验证数据和数据保存]
serializer.is_valid(raise_exception=True)
serializer.save()
# 4. 返回结果
return Response(serializer.data, status=status.HTTP_201_CREATED)
def destory(self, request, pk):
"""删除一个数据"""
# 1. 根据PK值获取要删除的数据并删除
self.get_object().delete()
# 2. 返回结果
return Response(status=status.HTTP_204_NO_CONTENT)
上面编写的视图方法list、create、retrieve、update、destroy依然要我们自己编写,但是定义的这些方法名与Mixins扩展类的5个类实现的方法是相同的,而这五个Mixins又依赖于GenericView,而GenericViewSet又继承至GenericView。所以我们继承GenericViewSet、5个Mixins扩展类即可省去这五个视图方法的编写
class _GenericViewSetView(GenericViewSet, ListModelMixin, CreateModelMixin, DestroyModelMixin, UpdateModelMixin,
RetrieveModelMixin):
queryset = BookInfo.objects.all()
serializer_class = BookSerializer
2、定义路由
urlpatterns = [
# --------------------GenericViewSet-----------------------------------------
path('demo/books/', _GenericViewSetView.as_view({
'get': 'list',
'post': 'create'
})),
re_path(r'^demo/books/(?P<pk>\d+)/$', _GenericViewSetView.as_view({
"get": 'retrieve',
'delete': 'destory',
'put': 'update'
})),
]
3、测试
三、ModelViewSet
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。如上面写的一样
class _ModelViewSet(ModelViewSet):
queryset = BookInfo.objects.all()
serializer_class = BookSerializer
#
# --------------------ModelViewSet-----------------------------------------
path('demo/books/', _ModelViewSet.as_view({
'get': 'list',
'post': 'create'
})),
re_path(r'^demo/books/(?P<pk>\d+)/$', _ModelViewSet.as_view({
"get": 'retrieve',
'delete': 'destroy',
'put': 'update'
})),
四、ReadOnlyModelViewSet
继承自GenericViewSet
,同时包括了ListModelMixin、RetrieveModelMixin。用于获取所有模型对象数据,单一模型对象数据