视图

Django REST framwork 提供的视图的主要作用:

  • 控制序列化器的执行(检验、保存、转换数据)
  • 控制数据库查询的执行

2个视图基类

APIView

  1. rest_framework.views.APIView

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

APIViewView的不同之处在于:

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

支持定义的属性

  • authentication_classes 列表或元祖,身份认证类
  • permissoin_classes 列表或元祖,权限检查类
  • throttle_classes 列表或元祖,流量控制类

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

举例:

  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. # url(r'^books/$', views.BookListView.as_view()),
  4. class BookListView(APIView):
  5. def get(self, request):
  6. books = BookInfo.objects.all()
  7. serializer = BookInfoSerializer(books, many=True)
  8. return Response(serializer.data)

GenericAPIView[通用视图类]

  1. rest_framework.generics.GenericAPIView

继承自APIVIew主要增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或多个Mixin扩展类。

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

  • 属性:

    • serializer_class 指明视图使用的序列化器
  • 方法:

    • get_serializer_class(self)

      当出现一个视图类中调用多个序列化器时,那么可以通过条件判断在get_serializer_class方法中通过返回不同的序列化器类名就可以让视图方法执行不同的序列化器对象了。

      返回序列化器类,默认返回serializer_class,可以重写,例如:

      1. def get_serializer_class(self):
      2. if self.request.user.is_staff:
      3. return FullAccountSerializer
      4. return BasicAccountSerializer
    • get_serializer(self, args, *kwargs)

      返回序列化器对象,主要用来提供给Mixin扩展类使用,如果我们在视图中想要获取序列化器对象,也可以直接调用此方法。

      注意,该方法在提供序列化器对象的时候,会向序列化器对象的context属性补充三个数据:request、format、view,这三个数据对象可以在定义序列化器时使用。

      • request 当前视图的请求对象
      • view 当前请求的类视图对象
      • format 当前请求期望返回的数据格式

提供的关于数据库查询的属性与方法

  • 属性:

    • queryset 指明使用的数据查询集
  • 方法:

    • get_queryset(self)

      返回视图使用的查询集,主要用来提供给Mixin扩展类使用,是列表视图与详情视图获取数据的基础,默认返回queryset属性,可以重写,例如:

      1. def get_queryset(self):
      2. user = self.request.user
      3. return user.accounts.all()
    • get_object(self)

      返回详情视图所需的模型类数据对象,主要用来提供给Mixin扩展类使用。

      在试图中可以调用该方法获取详情信息的模型类对象。

      若详情访问的模型类对象不存在,会返回404。

      该方法会默认使用APIView提供的check_object_permissions方法检查当前对象是否有权限被访问。

      举例:

      1. # url(r'^books/(?P<pk>\d+)/$', views.BookDetailView.as_view()),
      2. class BookDetailView(GenericAPIView):
      3. queryset = BookInfo.objects.all()
      4. serializer_class = BookInfoSerializer
      5. def get(self, request, pk):
      6. book = self.get_object() # get_object()方法根据pk参数查找queryset中的数据对象
      7. serializer = self.get_serializer(book)
      8. return Response(serializer.data)

其他可以设置的属性

  • pagination_class 指明分页控制类
  • filter_backends 指明过滤控制后端

5个视图扩展类

作用:

提供了几种后端视图(对数据资源进行曾删改查)处理流程的实现,如果需要编写的视图属于这五种,则视图可以通过继承相应的扩展类来复用代码,减少自己编写的代码量。

这五个扩展类需要搭配GenericAPIView父类,因为五个扩展类的实现需要调用GenericAPIView提供的序列化器与数据库查询的方法。

1)ListModelMixin

列表视图扩展类,提供list(request, *args, **kwargs)方法快速实现列表视图,返回200状态码。

该Mixin的list方法会对数据进行过滤和分页。

源代码:

  1. class ListModelMixin(object):
  2. """
  3. List a queryset.
  4. """
  5. def list(self, request, *args, **kwargs):
  6. # 过滤
  7. queryset = self.filter_queryset(self.get_queryset())
  8. # 分页
  9. page = self.paginate_queryset(queryset)
  10. if page is not None:
  11. serializer = self.get_serializer(page, many=True)
  12. return self.get_paginated_response(serializer.data)
  13. # 序列化
  14. serializer = self.get_serializer(queryset, many=True)
  15. return Response(serializer.data)

举例:

  1. from rest_framework.mixins import ListModelMixin
  2. class BookListView(ListModelMixin, GenericAPIView):
  3. queryset = BookInfo.objects.all()
  4. serializer_class = BookInfoSerializer
  5. def get(self, request):
  6. return self.list(request)

2)CreateModelMixin

创建视图扩展类,提供create(request, *args, **kwargs)方法快速实现创建资源的视图,成功返回201状态码。

如果序列化器对前端发送的数据验证失败,返回400错误。

源代码:

  1. class CreateModelMixin(object):
  2. """
  3. Create a model instance.
  4. """
  5. def create(self, request, *args, **kwargs):
  6. # 获取序列化器
  7. serializer = self.get_serializer(data=request.data)
  8. # 验证
  9. serializer.is_valid(raise_exception=True)
  10. # 保存
  11. self.perform_create(serializer)
  12. headers = self.get_success_headers(serializer.data)
  13. return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
  14. def perform_create(self, serializer):
  15. serializer.save()
  16. def get_success_headers(self, data):
  17. try:
  18. return {'Location': str(data[api_settings.URL_FIELD_NAME])}
  19. except (TypeError, KeyError):
  20. return {}

3) RetrieveModelMixin

详情视图扩展类,提供retrieve(request, *args, **kwargs)方法,可以快速实现返回一个存在的数据对象。

如果存在,返回200, 否则返回404。

源代码:

  1. class RetrieveModelMixin(object):
  2. """
  3. Retrieve a model instance.
  4. """
  5. def retrieve(self, request, *args, **kwargs):
  6. # 获取对象,会检查对象的权限
  7. instance = self.get_object()
  8. # 序列化
  9. serializer = self.get_serializer(instance)
  10. return Response(serializer.data)

举例:

  1. class BookDetailView(RetrieveModelMixin, GenericAPIView):
  2. queryset = BookInfo.objects.all()
  3. serializer_class = BookInfoSerializer
  4. def get(self, request, pk):
  5. return self.retrieve(request)

4)UpdateModelMixin

更新视图扩展类,提供update(request, *args, **kwargs)方法,可以快速实现更新一个存在的数据对象。

同时也提供partial_update(request, *args, **kwargs)方法,可以实现局部更新。

成功返回200,序列化器校验数据失败时,返回400错误。

源代码:

  1. class UpdateModelMixin(object):
  2. """
  3. Update a model instance.
  4. """
  5. def update(self, request, *args, **kwargs):
  6. partial = kwargs.pop('partial', False)
  7. instance = self.get_object()
  8. serializer = self.get_serializer(instance, data=request.data, partial=partial)
  9. serializer.is_valid(raise_exception=True)
  10. self.perform_update(serializer)
  11. if getattr(instance, '_prefetched_objects_cache', None):
  12. # If 'prefetch_related' has been applied to a queryset, we need to
  13. # forcibly invalidate the prefetch cache on the instance.
  14. instance._prefetched_objects_cache = {}
  15. return Response(serializer.data)
  16. def perform_update(self, serializer):
  17. serializer.save()
  18. def partial_update(self, request, *args, **kwargs):
  19. kwargs['partial'] = True
  20. return self.update(request, *args, **kwargs)

5)DestroyModelMixin

删除视图扩展类,提供destroy(request, *args, **kwargs)方法,可以快速实现删除一个存在的数据对象。

成功返回204,不存在返回404。

源代码:

  1. class DestroyModelMixin(object):
  2. """
  3. Destroy a model instance.
  4. """
  5. def destroy(self, request, *args, **kwargs):
  6. instance = self.get_object()
  7. self.perform_destroy(instance)
  8. return Response(status=status.HTTP_204_NO_CONTENT)
  9. def perform_destroy(self, instance):
  10. instance.delete()

几个子类视图

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

视图集ViewSet

使用视图集ViewSet,可以将一系列逻辑相关的动作放到一个类中:

  • list() 提供一组数据
  • retrieve() 提供单个数据
  • create() 创建数据
  • update() 保存数据
  • destory() 删除数据

ViewSet视图集类不再实现get()、post()等方法,而是实现动作 action 如 list() 、create() 等。

视图集只在使用as_view()方法的时候,才会将action动作与具体请求方式对应上。如:

  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)

在设置路由时,我们可以如下操作

  1. urlpatterns = [
  2. url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
  3. url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
  4. ]

常用视图集父类

1) ViewSet

继承自APIViewViewSetMixin,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典(如{'get':'list'})的映射处理工作。

在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

2)GenericViewSet

使用ViewSet通常并不方便,因为list、retrieve、create、update、destory等方法都需要自己编写,而这些方法与前面讲过的Mixin扩展类提供的方法同名,所以我们可以通过继承Mixin扩展类来复用这些方法而无需自己编写。但是Mixin扩展类依赖与GenericAPIView,所以还需要继承GenericAPIView

GenericViewSet就帮助我们完成了这样的继承工作,继承自GenericAPIViewViewSetMixin,在实现了调用as_view()时传入字典(如{'get':'list'})的映射处理工作的同时,还提供了GenericAPIView提供的基础方法,可以直接搭配Mixin扩展类使用。

举例:

  1. from rest_framework import mixins
  2. from rest_framework.viewsets import GenericViewSet
  3. from rest_framework.decorators import action
  4. class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
  5. queryset = BookInfo.objects.all()
  6. serializer_class = BookInfoSerializer

url的定义

  1. urlpatterns = [
  2. url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
  3. url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
  4. ]

3)ModelViewSet

继承自GenericViewSet,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

4)ReadOnlyModelViewSet

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

视图集中定义附加action动作

在视图集中,除了上述默认的方法动作外,还可以添加自定义动作。

举例:

  1. from rest_framework import mixins
  2. from rest_framework.viewsets import GenericViewSet
  3. from rest_framework.decorators import action
  4. class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
  5. queryset = BookInfo.objects.all()
  6. serializer_class = BookInfoSerializer
  7. def latest(self, request):
  8. """
  9. 返回最新的图书信息
  10. """
  11. book = BookInfo.objects.latest('id')
  12. serializer = self.get_serializer(book)
  13. return Response(serializer.data)
  14. def read(self, request, pk):
  15. """
  16. 修改图书的阅读量数据
  17. """
  18. book = self.get_object()
  19. book.bread = request.data.get('read')
  20. book.save()
  21. serializer = self.get_serializer(book)
  22. return Response(serializer.data)

url的定义

  1. urlpatterns = [
  2. url(r'^books/$', views.BookInfoViewSet.as_view({'get': 'list'})),
  3. url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
  4. url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),
  5. url(r'^books/(?P<pk>\d+)/read/$', views.BookInfoViewSet.as_view({'put': 'read'})),
  6. ]

action属性

在视图集中,我们可以通过action对象属性来获取当前请求视图集时的action动作是哪个。

例如:

  1. from rest_framework.viewsets import ModelViewSet,ReadOnlyModelViewSet
  2. from booktest.models import BookInfo
  3. from .serializers import BookInfoModelSerializer
  4. from rest_framework.response import Response
  5. class BookInfoModelViewSet(ModelViewSet):
  6. queryset = BookInfo.objects.all()
  7. serializer_class = BookInfoModelSerializer
  8. def get_top_5(self,request):
  9. """获取评论值最多的5条数据"""
  10. # 操作数据库
  11. print(self.action) # 获取本次请求的视图方法名
  12. 通过路由访问到当前方法中.可以看到本次的action就是请求的方法名

路由Routers

对于视图集ViewSet,我们除了可以自己手动指明请求方式与动作action之间的对应关系外,还可以使用Routers来帮助我们快速实现路由信息。

REST framework提供了两个router

  • SimpleRouter
  • DefaultRouter

使用方法

1) 创建router对象,并注册视图集,例如

  1. from rest_framework import routers
  2. router = routers.SimpleRouter()
  3. router.register(r'books', BookInfoViewSet, base_name='book')

register(prefix, viewset, base_name)

  • prefix 该视图集的路由前缀
  • viewset 视图集
  • base_name 路由名称的前缀

如上述代码会形成的路由如下:

  1. ^books/$ name: book-list
  2. ^books/{pk}/$ name: book-detail

2)添加路由数据

可以有两种方式:

  1. urlpatterns = [
  2. ...
  3. ]
  4. urlpatterns += router.urls

  1. urlpatterns = [
  2. ...
  3. url(r'^', include(router.urls))
  4. ]

视图集中附加action的声明

在视图集中,如果想要让Router自动帮助我们为自定义的动作生成路由信息,需要使用rest_framework.decorators.action装饰器。

以action装饰器装饰的方法名会作为action动作名,与list、retrieve等同。

action装饰器可以接收两个参数:

  • methods: 声明该action对应的请求方式,列表传递

  • detail
    声明该action的路径是否与单一资源对应,及是否是
    1. xxx/<pk>/action方法名/
    • True 表示路径格式是xxx/<pk>/action方法名/
    • False 表示路径格式是xxx/action方法名/

举例:

  1. from rest_framework import mixins
  2. from rest_framework.viewsets import GenericViewSet
  3. from rest_framework.decorators import action
  4. class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
  5. queryset = BookInfo.objects.all()
  6. serializer_class = BookInfoSerializer
  7. # detail为False 表示路径名格式应该为 books/latest/
  8. @action(methods=['get'], detail=False)
  9. def latest(self, request):
  10. """
  11. 返回最新的图书信息
  12. """
  13. ...
  14. # detail为True,表示路径名格式应该为 books/{pk}/read/
  15. @action(methods=['put'], detail=True)
  16. def read(self, request, pk):
  17. """
  18. 修改图书的阅读量数据
  19. """
  20. ...

由路由器自动为此视图集自定义action方法形成的路由会是如下内容:

  1. ^books/latest/$ name: book-latest
  2. ^books/{pk}/read/$ name: book-read

路由router形成URL的方式

1) SimpleRouter

2)DefaultRouter

DefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。

drf之视图类与路由的更多相关文章

  1. DRF之视图类(mixin)源码解析

     同样的增删改查操作,如果我们还像之前序列化组件那样做,代码重复率过多,所以我们用视图表示: 具体源码实现:首先定义一个视图类,然后根据mixin点进去有五个封装好的方法,这五个方法共有的属性就是都需 ...

  2. DRF介绍,DRF项目开发,DRF项目的视图类的dispatch源码解析

    目录 一.DRF介绍 1. 什么是DRF 2. 为什么要用DRF (1)使用DRF的原因 (2)站在开发者的角度来说用DRF的好处(暂时列举这么多) 二.用DRF开发后端项目 三.APIView请求生 ...

  3. FlaskCBV视图类

    路由视图类 from flask import Flask app = Flask(name) 视图类 Views文件 看views源码 继承最后一个类 导入CBV的视图基类 from flask i ...

  4. DRF的视图和路由

    DRF的视图 APIView Django中写CBV的时候继承的是View,rest_framework继承的是APIView, urlpatterns = [ url(r'^book$', Book ...

  5. DRF视图集的路由设置

    在使用DRF视图集时,往往需要配一大堆路由,例如: # views.py class DepartmentViewSet(ListModelMixin,CreateModelMixin,Retriev ...

  6. drf04 drf视图类

    REST framework 提供了众多的通用视图基类与扩展类,以简化视图的编写. 1.2个视图基类 1.1. APIView rest_framework.views.APIView APIView ...

  7. DRF框架之视图类

    前后端分离的项目 >: pip3 install djangorestframework   一.视图类传递参数给序列化类 视图层:views.py 需求: (1)在视图类中实列化对象是,可以设 ...

  8. 067.Python框架Django之DRF视图类

    一 关于视图类的一下概念 drf除了在数据序列化部分简写代码以外,还在视图中提供了简写操作.所以在django原有的django.views.View类基础上,drf封装了多个子类出来提供给我们使用. ...

  9. DRF 的视图,路由和渲染器

    DRF 的视图,路由和渲染器 1 视图 简单的增删改查 : ModelViewSet; 复杂的操作使用APIView 和 GenericViewSet APIView(View) class Home ...

随机推荐

  1. Codeforces Good Bye 2016 E. New Year and Old Subsequence

    传送门 题意: 给出一个长度为\(n\)的串,现在有\(q\)个询问,每个询问是一个区间\([l,r]\),要回答在区间\([l,r]\)中,最少需要删多少个数,满足区间中包含\(2017\)的子序列 ...

  2. css 高度随宽度比例变化

    [方案一:padding实现] 原理: 一个元素的 padding,如果值是一个百分比,那这个百分比是相对于其父元素的宽度而言的,padding-bottom 也是如此. 使用 padding-bot ...

  3. 解决opencart设置SSL后评论不能翻页的问题

    为了网站的安全和seo,我们为客户的opencart网站添加了SSL加密实现https,并设置了301跳转使http跳到https,基本所有的功能都完好,就是有一点评论分页无法加载分页,去分析了链接源 ...

  4. ajax jQ写的上传进度条

    XML/HTML Code <form id="myForm" action="upload.php" method="post" e ...

  5. 新版Notepad++加十六进制查看的插件HexEditor(转载+总结)

    用到hex文件查看,老版本的notepad++是可以安装的,新版本的是安装不了,这个差评啊, 但是网上有方法:https://github.com/chcg/NPP_HexEdit/releases下 ...

  6. 从一段文字中提取出uri信息

    package handle.groupby; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io ...

  7. 引入jquery时,页面一直加载

    注意jquery的引用位置最好放在<head>下面.

  8. 模拟赛 T1 费马小定理+质因数分解+exgcd

    求:$a^{bx \%p}\equiv 1(\mod p)$ 的一个可行的 $x$. 根据欧拉定理,我们知道 $a^{\phi(p)}\equiv 1(\mod p)$ 而在 $a^x\equiv 1 ...

  9. Scrapy的中间件(二)

    爬虫中间件 爬虫中间件的用法与下载器中间件非常相似,只是它们的作用对象不同.下载器中间件的作用对象是请求request和返回response:爬虫中间件的作用对象是爬虫,更具体地来说,就是写在spid ...

  10. idea开发工具

    IDEA简介 IDEA 全称 IntelliJ IDEA,是java编程语言开发的集成环境.IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手.代码自动提示.重构.J2EE支 ...