drf : 通用视图类和(GenericAPIView)5个视图扩展类,九个视图子类,视图集。
视图
REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写。
APIView
rest_framework.views.APIView
APIView
是REST framework提供的所有视图的基类,继承自Django的View
父类。
GenericAPIView使用[通用视图类]
继承自APIVIew
,主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。
点击第一层查看代码
from rest_framework.views import APIView
from .serizlizer import BookSerializers
from rest_framework.response import Response
from .models import Books
from rest_framework import status
from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer
class BookView(APIView):
renderer_classes = [JSONRenderer]
# 创建数据反序列化
def post(self, request):
print(request)
ser = BookSerializers(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
# 读取序列化
def get(self, request):
print(request)
book_list = Books.objects.all()
# many=True 代表序列化多条数据
ser = BookSerializers(instance=book_list, many=True)
"""
<class 'rest_framework.serializers.ListSerializer'>
ser 是ListSerializer的对象
"""
print(type(ser))
response = {'code': 100, 'msg': '查询成功', 'result': ser.data}
#
return Response(response, status=status.HTTP_202_ACCEPTED, headers={'name': 'junjie'})
# 查询单条
class BookDetailView(APIView):
def get(self, request, pk):
book = Books.objects.filter(pk=pk).first()
# 不传many默认为,many=False
ser = BookSerializers(instance=book)
"""
<class 'app01.serizlizer.BookSerializers'>
ser是BookSerializers的对象
"""
print(type(ser))
"""
BookSerializers(instance=<Books: Books object (1)>):
id = IntegerField(label='ID', read_only=True)
name = CharField(max_length=32)
price = IntegerField()
publish = PrimaryKeyRelatedField(allow_null=True, queryset=Publish.objects.all(), required=False)
"""
print(ser)
# 这一步才是真正将book_list转为字典并返回。调ser.data才是真正的序列化过程
return Response(ser.data)
# 删除单条数据
def delete(self, request, pk):
Books.objects.filter(pk=pk).delete()
return Response()
# 修改
def put(self, request, pk):
print(request)
book = Books.objects.filter(pk=pk).first()
# 得到模型层Book表对象。
print(book.name)
# {'name': '第11条数据', 'price': 20200, 'publish': 1} 反序列化数据。
print(request.data)
# 字典
print(type(request.data))
ser = BookSerializers(instance=book, data=request.data)
print(ser)
# <class 'app01.serizlizer.BookSerializers'>
print(type(ser))
if ser.is_valid():
ser.save()
return Response(ser.data)
class BookView(APIView):
renderer_classes = [JSONRenderer]
# 创建数据反序列化
def post(self, request):
ser = BookSerializers(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
# 读取序列化
def get(self, request):
book_list = Books.objects.all()
# many=True 代表序列化多条数据
ser = BookSerializers(instance=book_list, many=True)
response = {'code': 100, 'msg': '查询成功', 'result': ser.data}
return Response(response, status=status.HTTP_202_ACCEPTED, headers={'name': 'junjie'})
# 查询单条
class BookDetailView(APIView):
def get(self, request, pk):
book = Books.objects.filter(pk=pk).first()
ser = BookSerializers(instance=book)
return Response(ser.data)
def delete(self, request, pk):
Books.objects.filter(pk=pk).delete()
return Response()
# 修改
def put(self, request, pk):
book = Books.objects.filter(pk=pk).first()
ser = BookSerializers(instance=book, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
GenericAPIView[通用视图类]的方法属性以及方法,第二层的演变。
- 属性
serializer_class
指明视图使用的序列化器
- 方法
get_serializer_class(self)
现在来想继承GenericAPIView来写视图函数改如何写?先查看GenericAPIView类定义了什么属性和方法。
图书的五个接口,第二层,精简模型类和序列化类
from .models import Books, Publish
from rest_framework.generics import GenericAPIView
from .serizlizer import BookSerializers, PublishSerializers
from rest_framework.response import Response
class BookAPIView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request):
book_list = self.get_queryset()
ser = self.get_serializer(instance=book_list, many=True)
return Response(ser.data)
def post(self, request):
ser = self.get_serializer(data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
class BookDetailView(GenericAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request, pk):
book_list = self.get_object()
ser = self.get_serializer(instance=book_list)
return Response(ser.data)
def put(self, request, pk):
book_obj = self.get_object()
# 得到序列化类对象,传入单条对象和要修改的数据字段
ser = self.get_serializer(instance=book_obj, data=request.data)
if ser.is_valid():
ser.save()
return Response(ser.data)
def delete(self, request, pk):
book = self.get_object()
book.delete()
return Response()
如果想要再写一个视图类只需要继承GenericAPIView修改queryset和serializer_class即可,那么有没有别的方法可以节省代码?
使用GenericAPIView+5个视图扩展类。
from rest_framework.mixins import
CreateModelMixin, # 创建单个
ListModelMixin, # 查询所有
DestroyModelMixin, # 删除单个 碟嘶踹
UpdateModelMixin, # 新建单个
RetrieveModelMixin # 查询单个 瑞吹雾
代码如下:
from rest_framework.mixins import CreateModelMixin, UpdateModelMixin, DestroyModelMixin, RetrieveModelMixin, \
ListModelMixin
from rest_framework.generics import GenericAPIView
from .models import Books, Publish
from .serizlizer import BookSerializers, PublishSerializers
class BookAPIView(GenericAPIView,
# 创建数据
CreateModelMixin,
# 查看所有
ListModelMixin):
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request):
print(request)
return self.list(request)
def post(self, request):
return self.create(request)
class BookDetailView(GenericAPIView,
UpdateModelMixin, # 修改单条数据
DestroyModelMixin, # 删除单条
RetrieveModelMixin): # 查询单条
queryset = Books.objects.all()
serializer_class = BookSerializers
def get(self, request, pk):
print(request)
return self.retrieve(request, pk)
def delete(self, request, pk):
print(request)
return self.destroy(request, pk)
def put(self, request, pk):
return self.update(request, pk)
为什么叫视图扩展类:因为他不是视图类,视图类必须是继承View/APIView。
还有没有办法再精简代码?
GenericAPIView的视图子类,第三层
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
以及:
RetrieveAPIView, ListCreateAPIView, RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView
from rest_framework.generics import CreateAPIView, UpdateAPIView, DestroyAPIView, ListAPIView, RetrieveAPIView, \
ListCreateAPIView, RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView, RetrieveDestroyAPIView
class BookAPIView(ListCreateAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
class BookDetailAPIView(RetrieveUpdateDestroyAPIView):
queryset = Books.objects.all()
serializer_class = BookSerializers
总结:
#两个基类
APIView
GenericAPIView:有关数据库操作,queryset 和serializer_class
#5个视图扩展类(rest_framework.mixins)
CreateModelMixin:create方法创建一条
DestroyModelMixin:destory方法删除一条
ListModelMixin:list方法获取所有
RetrieveModelMixin:retrieve获取一条
UpdateModelMixin:update修改一条
#9个子类视图(rest_framework.generics)
CreateAPIView:继承CreateModelMixin,GenericAPIView,有post方法,新增数据
DestroyAPIView:继承DestroyModelMixin,GenericAPIView,有delete方法,删除数据
ListAPIView:继承ListModelMixin,GenericAPIView,有get方法获取所有
UpdateAPIView:继承UpdateModelMixin,GenericAPIView,有put和patch方法,修改数据
RetrieveAPIView:继承RetrieveModelMixin,GenericAPIView,有get方法,获取一条
ListCreateAPIView:继承ListModelMixin,CreateModelMixin,GenericAPIView,有get获取所有,post方法新增
RetrieveDestroyAPIView:继承RetrieveModelMixin,DestroyModelMixin,GenericAPIView,有get方法获取一条,delete方法删除
RetrieveUpdateAPIView:继承RetrieveModelMixin,UpdateModelMixin,GenericAPIView,有get获取一条,put,patch修改
RetrieveUpdateDestroyAPIView:继承RetrieveModelMixin,UpdateModelMixin,DestroyModelMixin,GenericAPIView,有get获取一条,put,patch修改,delete删除
第五层,直接写五个接口最终演示,自动生成路由。
from rest_framework.viewsets import ModelViewSet
# ModelViewSet继承了5个视图扩展类,GenericViewSet 和 ViewSetMixin
class BookAPIView(ModelViewSet):
queryset = Books.objects.all()
serializer_class = BookSerializers
继承五个视图扩展类的作用为用了五个接口方法。
GenericViewSet是什么?
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
"""
已知:generics.GenericAPIView 中有View和APIView,以及四个方法
def get_queryset(self):
def get_object(self):
def get_serializer(self, *args, **kwargs):
def get_serializer_class(self):
"""
ViewSetMixin
class ViewSetMixin:
@classonlymethod
def as_view(cls, actions=None, **initkwargs):
cls.name = None
cls.description = None
cls.suffix = None
cls.detail = None
cls.basename = None
# 注释:
"""
此处与url相对应,actions是什么?
path('books/', views.BookAPIView.as_view({'get':'list','post':'create'})),
actions = {'get':'list','post':'create'}
如果没有写则报异常。
"""
if not actions:
raise TypeError("The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`")
# 注释:
"""
字典.items()是将K,V拆出,此时method=K,action=V
以{'get':'list','post':'create'}举例。
get = method,list = action
"""
for method, action in actions.items():
# 注释:
"""
此时的self为视图类对象BookAPIView
action是上述所讲的url,as_view的第一个参数。
getattr反射,此时视图类对象中没有list,到父类ModelViewSet -->
mixins.ListModelMixin --> def list(self, request, *args, **kwargs):
handler 便是反射出来的list
setattr设置值,将list映射成get,视图中的get方法实质上是list方法。
客户端发送get请求就能找到list
这里主要用作区分用户是查询单条还是查询所有
"""
handler = getattr(self, action)
setattr(self, method, handler)
self.request = request
self.args = args
self.kwargs = kwargs
# And continue as usual
return self.dispatch(request, *args, **kwargs)
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
# We need to set these on the view function, so that breadcrumb
# generation can pick out these bits of information from a
# resolved URL.
view.cls = cls
view.initkwargs = initkwargs
view.actions = actions
return csrf_exempt(view)
第五层
导入模块
from rest_framework.viewsets import ModelViewSet
直接写五个接口最终演示,自动生成路由。
from rest_framework.viewsets import ModelViewSet, ReadOnlyModelViewSet, GenericViewSet, ViewSet
# 直接写五个接口,一定要继承(ViewSetMixin),才能自动生成路由
# class BookAPIView(ModelViewSet):
# queryset = Books.objects.all()
# serializer_class = BookSerializers
# 查询所有和查询单个,如果只继承了ReadOnlyModelViewSet,路由也需要更改。
# class BookAPIView(ReadOnlyModelViewSet):
# queryset = Books.objects.all()
# serializer_class = BookSerializers
# GenericViewSet:继承了(ViewSetMixin, generics.GenericAPIView)
# ViewSet:继承了(ViewSetMixin, views.APIView)
class BookAPIView(ViewSet):
def xjz(self, request):
return Response("junjie")
url
# 自动生成路由
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
# 必须继承(ViewSetMixin),才能自动生成路由
router.register('books', views.BookAPIView)
urlpatterns = [
path('admin/', admin.site.urls),
# 将请求映射到对应的方法
path('books/', views.BookAPIView.as_view({'get':'list'})),
path('books/<int:pk>', views.BookAPIView.as_view({'get':'retrieve'})),
]
urlpatterns += router.urls
导入模块
from rest_framework.routers import SimpleRouter
from django.urls import path,include
router = SimpleRouter()
# 必须继承(ViewSetMixin),才能自动生成路由
router.register('admin', views.BookAPIView)
urlpatterns = [
# path('admin/', admin.site.urls),
path('api/',include(router.urls))
]
此时浏览器访问admin的路由:http://127.0.0.1:8000/api/admin/