Django Rest Framework 视图集

视图集ViewSet

视图集的继承关系
视图集类继承关系.png
两个基本视图集
视图集 继承自
Viewset APIView,ViewSetMixin
GenricViewset GenericAPIView,ViewSetMixin
  • ViewSet
    • 在ViewSet中,没有提供任何动作action方法,需自己实现动作action( list() 、create() 等)
    • 因为继承自ViewSetMixin,实现了将请求方式和action动作在as_view中进行映射,键值对中,值可以相同,键必须不同
      as_view({'请求方式1':'action动作1','请求方式2':'action动作2',})
  • GenricViewSet
class BooksViewSet(ViewSet):
    def list(self, request):
        #获取所有数据
        books = BookInfo.objects.all()
        ser = BookSerializers(books, many=True)
        return Response(ser.data)

    def create(self, request):
        #保存数据
        data = request.data
        ser = BookSerializers(data=data)
        ser.is_valid(raise_exception=True)
        ser.save()
        return Response(ser.data)

    def last(self, request):
        #返回最后一本图书信息
        book = BookInfo.objects.last()
        ser = BookSerializers(book)
        return Response(ser.data)

    def show(self, request, pk):
        #获取指定数据
        book = BookInfo.objects.get(id=pk)
        ser = BookSerializers(book)
        return Response(ser.data)
两个扩展视图集
扩展视图集 继承自
ModelViewset GenricViewset,五个扩展类
ReadOnlyModelViewSet GenricViewset,ListModelMixin,RetrieveModelMixin
  • ModelViewset
    • 继承自GenericAPIVIew、ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin
  • ReadOnlyModelViewSet
    • 参与序列化返回,所以继承自查询单个数据和查询所有数据的扩展类
#定义一个分页
class PageNum(PageNumberPagination):
    page_size_query_param = 'page_size'  #指定控制页面展示数量的参数
    max_page_size = 8  #最大返回多少条数据

class BooksModelViewSet(ModelViewSet):
    serializer_class = BookSerializers
    queryset = BookInfo.objects.all()
    #局部认证属性
    # authentication_classes = [BasicAuthentication, SessionAuthentication]
    #局部权限属性
    # permission_classes = [IsAuthenticated]
    #局部限流属性
    # throttle_classes = [UserRateThrottle]
    #对视图进行限流命名, 在setting.py中进行限流次数的指定
    # throttle_scope = 'shows'
    #过滤字段指定
    # filter_fields = ('btitle', 'bread')
    # #排序过滤
    # #指定过滤的类方法
    # filter_backends = [OrderingFilter]
    # #针对排序的字段定义
    # ordering_fields = ['id', 'bread']
    #局部配置 分页属性
    # pagination_class = PageNum

    @action(methods=['get'], detail=True)
    def show(self, request, pk):
        #手动抛出一个异常
        # raise DataError
        #获取指定数据
        book = self.get_object()
        ser = self.get_serializer(book)
        return Response(ser.data)
视图集自定义action动作

在视图集中,除了默认的动作(list() 提供一组数据,retrieve() 提供单个数据,create() 创建数据,update() 保存数据,destory() 删除数据)外,可以自定义动作

  • 添加自定义动作时,需要rest_framework.decorators.action装饰器
  • 在自定义动作方法上,添加@action(),接收两个参数
    • methods,该action支持的请求方式,列表传递
    • detail,action中要处理的是否是视图资源的对象(即是否通过url路径获取主键)
      • True 表示使用通过URL获取的主键对应的数据对象
      • False 表示不使用URL获取主键

路由Router

SimpleRouter
  1. 创建router,并注册视图集
  • register(prefix, viewset, base_name)
    • prefix 该视图集的路由前缀
    • viewset 视图集
    • base_name 路由名称的前缀
from rest_framework import routers

router = routers.SimpleRouter()
router.register(r'books', BookInfoViewSet, base_name='book')
  1. 添加路由数据
  • 在注册之后,urlpatterns += router.urls
  • 直接在urlpatterns中includerouter.url
    • url(r'^', include(router.urls))
  1. 视图集中使用装饰器@action,在视图类内自定义的方法上添加自动生成路由
  • @action(methods=['get'], detail=False)
    • detail为False,生成的路由中不会有正则匹配(方法中不接收参数)
    • detail为True,生成的路由中有正则匹配(方法中接收参数)
DefaultRouter

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

因为视图集继承自ViewSetMixin,才有action属性,装饰器和自动生成路由的方法

认证,权限和限流属性(APIView)

  • authentication_classes认证属性
    • 全局认证,在settings.py的REST_FRAMEWORK中定义 'DEFAULT_AUTHENTICATION_CLASSES'
    • 局部认证,在类视图中定义authentication_classes = (SessionAuthentication, BasicAuthentication)
  • permission_classes 权限认证
    • 权限控制可以限制用户对于视图的访问和对于具体数据对象的访问
      • 在执行视图的dispatch()方法前,会先进行视图访问权限的判断
      • 在通过get_object()获取具体对象时,会进行对象访问权限的判断
    • 提供的权限
      • AllowAny 允许所有用户
      • IsAuthenticated 仅通过认证的用户
      • IsAdminUser 仅管理员用户
      • IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能get读取
    • 全局配置,在settings.py的REST_FRAMEWORK中定义 'DEFAULT_PERMISSION_CLASSES',
    • 局部配置,在类视图中定义permission_classes = (IsAuthenticated,)
  • throttle_classes限流属性
    • 全局配置,在settings.py的REST_FRAMEWORK中定义DEFAULT_THROTTLE_CLASSES (限流类)和 DEFAULT_THROTTLE_RATES(限流周期)
      • 可选限流类
        • AnonRateThrottle,限制所有匿名未认证用户,DEFAULT_THROTTLE_RATES['anon'] 来设置频次
        • UserRateThrottle,限制认证用户,DEFAULT_THROTTLE_RATES['user'] 来设置频次
        • ScopedRateThrottle,限制用户对于每个视图的访问频次,在视图类中用throttle_scope起别名,在settings.py中对别名进行频次设置
    • 局部配置,在类视图中定义throttle_classess=(UserRateThrottle,)

过滤与排序属性

  • 过滤
    • 安装django-filter
    pip insall django-filter
    
    • 将django-filter在settings.py中注册应用
    • 在settings.py中的REST_FRAMEWORK,定义'DEFAULT_FILTER_BACKENDS'
    • 在视图中添加filter_fields属性,指定可以过滤的字段
    • 在浏览器进行访问时,?字段=查询内容
  • 排序
    • 在试图类中设置filter_backends,使用rest_framework.filters.OrderingFilter过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering参数指明的排序字段对数据集进行排序。
    • 前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
    • 不用在settings.py中做任何配置
    • 浏览器访问时,通过?ordering=字段,从小到大,-字段,从大到小
filter_backends = [OrderingFilter]
    ordering_fields = ('id', 'bread', 'bpub_date')
  • 过滤和排序不能同时使用

分页,异常处理和自动生成接口文档

  • 分页
    • 全局配置
      REST_FRAMEWORK = {
          'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
          'PAGE_SIZE': 100  # 每页数目
      }
      
    • 局部配置
      -自定义Pagination类,为视图添加分页行为
      class LargeResultsSetPagination(PageNumberPagination):
          page_size = 1000
          page_size_query_param = 'page_size'
          max_page_size = 10000
      class BookDetailView(RetrieveAPIView):
          queryset = BookInfo.objects.all()
          serializer_class = BookInfoSerializer
          pagination_class = LargeResultsSetPagination
      
      • 可选分页器
        page_size 每页数目
        page_query_param 前端发送的页数关键字名,默认为"page"
        page_size_query_param 前端发送的每页数目关键字名,默认为None
        max_page_size 前端最多能设置的每页数量
        
        from rest_framework.pagination import PageNumberPagination
        
        class StandardPageNumberPagination(PageNumberPagination):
            page_size_query_param = 'page_size'
            max_page_size = 10
        
        class BookListView(ListAPIView):
            queryset = BookInfo.objects.all().order_by('id')
            serializer_class = BookInfoSerializer
            pagination_class = StandardPageNumberPagination
        
        # 127.0.0.1/books/?page=1&page_size=2
        
        default_limit 默认限制,默认值与PAGE_SIZE设置一直
        limit_query_param limit参数名,默认'limit'
        offset_query_param offset参数名,默认'offset'
        max_limit 最大limit限制,默认None
        
        from rest_framework.pagination import LimitOffsetPagination
        class BookListView(ListAPIView):
            queryset = BookInfo.objects.all().order_by('id')
            serializer_class = BookInfoSerializer
            pagination_class = LimitOffsetPagination
        
        # 127.0.0.1:8000/books/?offset=3&limit=2
        
  • 异常处理
    • 自定义异常处理
      #在类视图方法中先手动抛出异常
      
      #定义异常处理方法
      from rest_framework.views import exception_handler as drf_exception_handler
      
      def exception_handler(exc, context):
          # 先调用REST framework默认的异常处理方法获得标准错误响应对象
          response = drf_exception_handler(exc, context)
      
          # 在此处补充自定义的异常处理
          if response is None:
              view = context['view']
              if isinstance(exc, DataError):
                  print('[%s]: %s' % (view, exc))
                  response = Response({'detail': '服务器内部错误'},
                           status=status.HTTP_507_INSUFFICIENT_STORAGE)
      
          return response
      
      #在配置文件中声明
      REST_FRAMEWORK = {
          'EXCEPTION_HANDLER': 'book.utils.exception_handler'
      }
      
  • 自动生成接口文档
    • 接口文档以网页的方式呈现,自动接口文档能生成的是继承自APIView及其子类的视图

    • 安装依赖

      pip install coreapi

    • 设置接口文档访问路径

      • 在总路由中添加接口文档路径
      • 文档路由对应的视图配置为rest_framework.documentation.include_docs_urls
      from rest_framework.documentation import include_docs_urls
      
      urlpatterns = [
          ...
          url(r'^docs/', include_docs_urls(title='My API title'))
      ]
      
    • 文档描述说明的定义位置

      • 单一方法的视图,可直接使用类视图的文档字符串

        class BookListView(generics.ListAPIView):
            """
            返回所有图书信息.
            """
        
      • 包含多个方法的视图,在类视图的文档字符串中,分开方法定义

        class BookListCreateView(generics.ListCreateAPIView):
            """
            get:
            返回所有图书信息.
            post:
            新建图书.
            """
        
      • 对于视图集ViewSet,仍在类视图的文档字符串中分开定义,但是应使用action名称区分

        class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
            """
            list:
            返回图书列表数据
            retrieve:
            返回图书详情数据
            latest:
            返回最新的图书数据
            read:
            修改图书的阅读量
            """
        
    • 访问接口文档网页

      • 浏览器访问 127.0.0.1:8000/docs/,即可看到自动生成的接口文档
      • 视图集ViewSet中的retrieve名称,在接口文档网站中叫做read
      • 参数的Description需要在模型类或序列化器类的字段中以help_text选项定义
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容