视图的用法
1.DRF中的request以及response
DRF中传入视图的request对象 不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。
DRF中传入视图的response对象 REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。
添加配置文件
- REST_FRAMEWORK = {
- ‘DEFAULT_RENDERER_CLASSES‘: ( # 默认响应渲染类
- ‘rest_framework.renderers.JSONRenderer‘, # json渲染器
- ‘rest_framework.renderers.BrowsableAPIRenderer‘, # 浏览API渲染器
- )
- }
2.DRF中的视图的优势
首先我们来看不使用DRF,视图怎么实现
通用视图基类与扩展类,以简化视图的编写
- # 处理admin站点的请求
- class BooksAPIView(View):
- # GET /books/
- def get(self, request):
- books = BookInfo.objects.all()
- book_list = []
- for book in books:
- book_list.append({
- ‘id‘: book.id,
- ‘btitle‘: book.btitle,
- ‘bread‘: book.bread,
- ‘bcomment‘: book.bcomment,
- ‘is_delete‘: book.is_delete,
- # 注意此处要加上url才能访问到图片的地址
- ‘image‘: book.image.url if book.image else ‘‘,
- ‘bpub_date‘: book.bpub_date
- })
- return JsonResponse(book_list, safe=False)
代码块1
怎么样,是不是感觉很复杂。我们的DRF就可以帮我们处理其中的大部分代码而不用我们自己去处理!!!
重点来了,怎么实现呢?
首先我们得了解一下,当我们不去自己继承View类定义类视图时,DRF给哦们提供了几个继承自View类的丰富的类
1.基类:APIView
APIView是REST framework提供的所有视图的基类,继承自Django的View
父类。
APIView
与View
的不同之处在于:
- 传入到视图方法中的是REST framework的
Request
对象,而不是Django的HttpRequeset
对象; - 视图方法可以返回REST framework的
Response
对象,视图会为响应数据设置(render)符合前端要求的格式; - 任何
APIException
异常都会被捕获到,并且处理成合适的响应信息; - 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。
支持定义的属性:
- authentication_classes 列表或元祖,身份认证类
- permissoin_classes 列表或元祖,权限检查类
- throttle_classes 列表或元祖,流量控制类
在APIView
中仍和普通的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。
- class BookListView(APIView):
- """使用APIView实现“获取所有图书信息”接口"""
- def get(self, request):
- """
- 获取所有图书信息
- GET /books/
- :param request: Request类型的对象
- :return: JSON
- """
- qs = BookInfo.objects.all() # 查询要序列化的模型数据
- serializer = BookInfoSerializer(qs, many=True) # 准备序列化器:将模型数据转字典数据
- return Response(serializer.data) # 响应序列化的结果
代码块2
对比代码块1,发现确实工作量减少很多
2.基类:GenericAPIView
提供的关于序列化器使用的属性与方法
具体实现例子:
- class BookListView(GenericAPIView):
- """使用GenericAPIView实现“获取所有图书信息”接口"""
- serializer_class = BookInfoSerializer # 指定序列化器
- queryset = BookInfo.objects.all() # 指定查询集
- def get(self, reqeust):
- """
- 获取所有图书信息
- GET /books/
- :param reqeust: Request类型的对象
- :return: JSON
- """
- qs = self.get_queryset() # 获取查询集
- serializer = self.get_serializer(qs, many=True)# 创建序列化器对象
- return Response(serializer.data) # 响应序列化后的数据
我们发现这样做反而增加了两行代码,怎么说他优化了呢?别急,下边的GenericAPIView扩展类要大显身手了
3.配合GenericAPIView使用的几个扩展类
我们发现前边的两个父类还需要进行函数的定义去处理不同的请求,这样我们还得在函数里边实现查询集以及序列化器的指定,工作量仍然很大。怎么解决呢?
GenericAPIView的五个扩展类给我们提供了五个方法分别进行增删改查的不同操作,这样我们就不用写那么多函数啦!!
五个扩展类(为啥是5个?答:增删改查,查有两个)
搭配GenericAPIView使用
1.ListModelMixin: 提供list方法快速实现列表视图
2.CreateModelMixin: 提供create方法快速实现创建资源的视图
3.RetrieveModelMixin 提供retrieve方法,可以快速实现返回一个存在的数据对象(需要传入pk)
4.UpdateModelMixin 提供update方法,可以快速实现更新一个存在的数据对象。 提供partial_update方法,可以实现局部更新
5.DestroyModelMixin 提供destroy方法,可以快速实现删除一个存在的数据对象
一个例子:
- class BookDetailView(mixins.RetrieveModelMixin, GenericAPIView):
- """使用GenericAPIView实现“获取单一图书信息”接口"""
- serializer_class = BookInfoSerializer # 指定序列化器
- queryset = BookInfo.objects.all() # 指定查询集
- def get(self, request, pk):
- """
- 获取单一图书信息
- GET /books/<pk>/
- :param request: Request类型的对象
- :return: JSON
- """
- return self.retrieve(request)
看到没有,函数里边只有一行代码了,简化了吧!明显看得出来,这个父类帮我们吧return之前的事情都做了
GenericAPIView搭配扩展类的使用的优势就显示出来了
我想说的是:这里还能简化!!!
1.CreateAPIView(等价于GenericAPIView+CreateModelMixin) 提供 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
所以代码中的mixins.RetrieveModelMixin, GenericAPIView可以写成RetrieveAPIView
4.视图集父类1:ViewSet
那么能否继续优化呢?答案:能!!!
前边的父类仍需要写很多函数,这些函数定义仍然增加我们的工作量
ViewSet:将几个操作放在一起(前边的方法都是分开实现的)
list() 提供一组数据
retrieve() 提供单个数据
create() 创建数据
update() 保存数据
destory() 删除数据
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{‘get‘:‘list‘}
)的映射处理工作。
在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。
ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。
如:
- class BookInfoViewSet(viewsets.ViewSet):
- def list(self, request):
- books = BookInfo.objects.all()
- serializer = BookInfoSerializer(books, many=True)
- return Response(serializer.data)
- def retrieve(self, request, pk=None):
- try:
- books = BookInfo.objects.get(id=pk)
- except BookInfo.DoesNotExist:
- return Response(status=status.HTTP_404_NOT_FOUND)
- serializer = BookInfoSerializer(books)
- return Response(serializer.data)
视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上
如:
url(r‘^books/$‘, BookInfoViewSet.as_view({‘get‘:‘list‘}),
url(r‘^books/(?P<pk>\d+)/$‘, BookInfoViewSet.as_view({‘get‘: ‘retrieve‘})
5.视图集父类2:GenericViewSet
使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView。
- class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
- queryset = BookInfo.objects.all()
- serializer_class = BookInfoSerializer
设置url:
- url(r‘^books/$‘, views.BookInfoViewSet.as_view({‘get‘: ‘list‘})),
- url(r‘^books/(?P<pk>\d+)/$‘, views.BookInfoViewSet.as_view({‘get‘: ‘retrieve‘}))
6.视图集父类3:ModelViewSet
只需定义
queryset = BookInfo.objects.all()
serializer_class = BookInfoAllSerializer
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
- class BookInfoViewSet(ModelViewSet):
- queryset = BookInfo.objects.all()
- serializer_class = BookInfoAllSerializer
7.视图集父类4:ReadOnlyModelViewSet
继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin
- class BookInfoViewSet(ReadOnlyModelViewSet):
- """使用视图集实现返回列表和单一数据"""
- # 指定序列化器
- serializer_class = BookInfoSerializer
- # 指定查询集
- queryset = BookInfo.objects.all()
- # detail为False 表示路径名格式应该为 books/latest/
- @action(methods=[‘get‘], detail=False)
- def latest(self, request):
- """
- 自定义action: 返回最新的图书信息
- GET /books/latest/
- """
- # latest : 先将数据根据‘id‘倒叙,再取第0个
- book = BookInfo.objects.latest(‘id‘)
- serializer = self.get_serializer(book)
- return Response(serializer.data)
8.路由router
当我们完成上述工作后,发现路由默认5个,加上自己配置的有很多路由,每自定义一个新的方法时就得配置路由。
DRF提供了路由:Routers
快速实现路由 Routers主要有两个: SimpleRouter DefaultRouter
DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。
使用: register(prefix, viewset, base_name)
prefix 该视图集的路由前缀
viewset 视图集
base_name 路由名称的前缀
在路由文件中创建router对象,并注册视图集,最后把视图加到urlpatterns中 如:
# 给视图集定义路由
router = DefaultRouter()
router.register(r‘books‘, views.BookInfoViewSet)
# 将DRF生成的路由信息,添加到urlpatterns
urlpatterns += router.urls
原文地址:https://www.cnblogs.com/whkzm/p/12142151.html