def --- DRF视图的详细用法

视图的用法

1.DRF中的request以及response

DRF中传入视图的request对象 不再是Django默认的HttpRequest对象,而是REST framework提供的扩展了HttpRequest类的Request类的对象。

DRF中传入视图的response对象 REST framework提供了一个响应类Response,使用该类构造响应对象时,响应的具体数据内容会被转换(render渲染)成符合前端需求的类型。

添加配置文件


   
   
  1. REST_FRAMEWORK = {
  2. 'DEFAULT_RENDERER_CLASSES': ( # 默认响应渲染类
  3. 'rest_framework.renderers.JSONRenderer', # json渲染器
  4. 'rest_framework.renderers.BrowsableAPIRenderer', # 浏览API渲染器
  5. )
  6. }

2.DRF中的视图的优势

首先我们来看不使用DRF,视图怎么实现

通用视图基类与扩展类,以简化视图的编写


   
   
  1. # 处理admin站点的请求
  2. class BooksAPIView(View):
  3. # GET /books/
  4. def get(self, request):
  5. books = BookInfo.objects.all()
  6. book_list = []
  7. for book in books:
  8. book_list.append({
  9. 'id': book.id,
  10. 'btitle': book.btitle,
  11. 'bread': book.bread,
  12. 'bcomment': book.bcomment,
  13. 'is_delete': book.is_delete,
  14. # 注意此处要加上url才能访问到图片的地址
  15. 'image': book.image.url if book.image else '',
  16. 'bpub_date': book.bpub_date
  17. })
  18. return JsonResponse(book_list, safe= False)

                                                                                       代码块1

怎么样,是不是感觉很复杂。我们的DRF就可以帮我们处理其中的大部分代码而不用我们自己去处理!!!

重点来了,怎么实现呢?

首先我们得了解一下,当我们不去自己继承View类定义类视图时,DRF给哦们提供了几个继承自View类的丰富的类

1.基类:APIView

APIView是REST framework提供的所有视图的基类,继承自Django的View父类。

APIViewView的不同之处在于:

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;
  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;
  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;
  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制

支持定义的属性:

扫描二维码关注公众号,回复: 8399424 查看本文章
  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类

APIView中仍和普通的类视图定义方法来实现get() 、post() 或者其他请求方式的方法。


   
   
  1. class BookListView(APIView):
  2. """使用APIView实现“获取所有图书信息”接口"""
  3. def get(self, request):
  4. """
  5. 获取所有图书信息
  6. GET /books/
  7. :param request: Request类型的对象
  8. :return: JSON
  9. """
  10. qs = BookInfo.objects.all() # 查询要序列化的模型数据
  11. serializer = BookInfoSerializer(qs, many= True) # 准备序列化器:将模型数据转字典数据
  12. return Response(serializer.data) # 响应序列化的结果

                                                                                  代码块2

 对比代码块1,发现确实工作量减少很多

2.基类:GenericAPIView

提供的关于序列化器使用的属性与方法

 具体实现例子:


   
   
  1. class BookListView(GenericAPIView):
  2. """使用GenericAPIView实现“获取所有图书信息”接口"""
  3. serializer_class = BookInfoSerializer # 指定序列化器
  4. queryset = BookInfo.objects.all() # 指定查询集
  5. def get(self, reqeust):
  6. """
  7. 获取所有图书信息
  8. GET /books/
  9. :param reqeust: Request类型的对象
  10. :return: JSON
  11. """
  12. qs = self.get_queryset() # 获取查询集
  13. serializer = self.get_serializer(qs, many= True) # 创建序列化器对象
  14. 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方法,可以快速实现删除一个存在的数据对象

一个例子:


   
   
  1. class BookDetailView(mixins.RetrieveModelMixin, GenericAPIView):
  2. """使用GenericAPIView实现“获取单一图书信息”接口"""
  3. serializer_class = BookInfoSerializer # 指定序列化器
  4. queryset = BookInfo.objects.all() # 指定查询集
  5. def get(self, request, pk):
  6. """
  7. 获取单一图书信息
  8. GET /books/<pk>/
  9. :param request: Request类型的对象
  10. :return: JSON
  11. """
  12. 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() 等。

如:


   
   
  1. class BookInfoViewSet(viewsets.ViewSet):
  2. def list(self, request):
  3. books = BookInfo.objects.all()
  4. serializer = BookInfoSerializer(books, many= True)
  5. return Response(serializer.data)
  6. def retrieve(self, request, pk=None):
  7. try:
  8. books = BookInfo.objects.get(id=pk)
  9. except BookInfo.DoesNotExist:
  10. return Response(status=status.HTTP_404_NOT_FOUND)
  11. serializer = BookInfoSerializer(books)
  12. 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。


   
   
  1. class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
  2. queryset = BookInfo.objects.all()
  3. serializer_class = BookInfoSerializer

 设置url:


   
   
  1. url( r'^books/$', views.BookInfoViewSet.as_view({ 'get': 'list'})),
  2. 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。


   
   
  1. class BookInfoViewSet(ModelViewSet):
  2. queryset = BookInfo.objects.all()
  3. serializer_class = BookInfoAllSerializer

7.视图集父类4:ReadOnlyModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin


   
   
  1. class BookInfoViewSet(ReadOnlyModelViewSet):
  2. """使用视图集实现返回列表和单一数据"""
  3. # 指定序列化器
  4. serializer_class = BookInfoSerializer
  5. # 指定查询集
  6. queryset = BookInfo.objects.all()
  7. # detail为False 表示路径名格式应该为 books/latest/
  8. @action(methods=['get'], detail=False)
  9. def latest(self, request):
  10. """
  11. 自定义action: 返回最新的图书信息
  12. GET /books/latest/
  13. """
  14. # latest : 先将数据根据'id'倒叙,再取第0个
  15. book = BookInfo.objects.latest( 'id')
  16. serializer = self.get_serializer(book)
  17. 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

猜你喜欢

转载自www.cnblogs.com/whkzm/p/12142151.html
def
今日推荐