返回顶部
首页 > 资讯 > 后端开发 > Python >Rest_framework Route
  • 960
分享到

Rest_framework Route

Rest_frameworkRoute 2023-01-30 23:01:07 960人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录 Rest_framework Router 路由器 ViewSet结合Router,自动生成url。 将ViewSet注册到Router中,需

目录

  • Rest_framework Router 路由器
    • ViewSet结合Router,自动生成url。
      • 将ViewSet注册到Router中,需要三个要素:
      • 关于路由规则,细分有四类:
    • rest_framework.routers.SimpleRouter源码解析
      • SimpleRouter继承和方法一览
      • SimpleRouter类源码
    • 总结

虽说Django rest_framework是基于djanGo的,url路由到视图主要还是利用django的dispatcher路由系统(可以参考我的另一篇关于django url dispatcher详解),但是rest_framework还在django路由的基础上,提供了基于restful风格的更高等级的路由方式。就是Http method 路由到 actions 的映射关系(一个字典)。而在rest_framework中实现这层路由方式的是rest_framework.viewsets.ViewSetMinix类实现。另一方面由于restful风格面向的资源无非单资源或者资源集。常用的actions操作create,list, retreive,update, destroy。所以对于单资源和资源集都有相对固定的操作模式和url风格模式,所以抽象出来这样一种结合两种路由的一条龙模式:Router 路由器,单资源url与资源集合url的pattern及其对应的http method 映射 actions,都通过Router自动生成。
Router路由器的功能就是自动生成url。
其实Router就是利用ViewSetMinix根据methods与actions的一个mapping,再按照单资源或资源集的url的通常操作action类型,相结合起来,产生出一个route 即一条路由规则的概念。
下面就结合一条route就定义了产生实际url路由和相应的对url的操作映射。

ViewSet结合Router,自动生成url。

将ViewSet注册到Router中,需要三个要素:

  1. prefix前缀或者叫资源集名。用于url中表示资源集名。类型:正则字符串
  2. viewset视图类。继承了ViewSetMinix类。类型:is-a ViewSetMinix
  3. basename 用于生成url的url名称。不提供会根据queryset的model名作为其值。类型:字符串。如:users-list/users-create等等

Router.reGISter() 接口提供注册。

关于路由规则,细分有四类:

一条路由规则就是一个Route对象,实例Route对象的参数不同,划分了四类(DynamicRoute也算类Route类):

  1. 一般detail,提供的(retrieve,update,destroy,partial_update),单资源的操作路由
  2. 一般list (list, create) , 资源集的操作路由
  3. 动态detail (通过@action装饰器), 单资源的额外操作
  4. 动态list (通过@aciton装饰器)

这四类路由完全能满足,各种大多路由需求。

四种路由规则如下:

routes = [  
        # List route.
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={
                'get': 'list',
                'post': 'create'
            },
            name='{basename}-list',
            detail=False,       # 注意这里detail是false说明是list路由
            initkwargs={'suffix': 'List'}
        ),
        # Dynamically generated list routes. Generated using
        # @action(detail=False) decorator on methods of the viewset.
        DynamicRoute(   #动态的list路由
            url=r'^{prefix}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
        # Detail route.
        Route(  
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            },
            name='{basename}-detail',
            detail=True,  #说明是detail路由
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamically generated detail routes. Generated using
        # @action(detail=True) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,   # 动态detail路由
            initkwargs={}
        ),
    ]

路由规则中,可以修改非动态路由的mapping,从而可以自定义路由。
将VIewSet注册到Router中后,就可通过Router.urls获取自动生成的url列表。
具体自动生成urls原理,见下面源码解析。

rest_framework.routers.SimpleRouter源码解析

主要通过源码简单分析,印证本文上面内容的表达

SimpleRouter继承和方法一览

SimpleRouter类源码

浅析请看注释

class SimpleRouter(BaseRouter):  # BaseRouter提供了一个property是urls,其大多会调用get_urls()

    routes = [                                     # 上面提到的4条route对象
        # List route.
        Route(
            url=r'^{prefix}{trailing_slash}$',  # 集合资源路由url
            mapping={                           # 集合资源 符合restful风格 的操作 http methods 与 actions映射
                'get': 'list',
                'post': 'create'
            },
            name='{basename}-list',          # 路由名,注意s字符串都是格式化字符串,字符串的格式化会发生在get_urls方法遍历routes时
            detail=False,                        # 注意这里detail是false说明是list路由
            initkwargs={'suffix': 'List'}
        ),
        # Dynamically generated list routes. Generated using
        # @action(detail=False) decorator on methods of the viewset.
        DynamicRoute(                          # 动态的list路由
            url=r'^{prefix}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
        # Detail route.
        Route(  
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',
                'put': 'update',
                'patch': 'partial_update',
                'delete': 'destroy'
            },
            name='{basename}-detail',
            detail=True,                            #说明是detail路由
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamically generated detail routes. Generated using
        # @action(detail=True) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,                            # 动态detail路由
            initkwargs={}
        ),
    ]

    def __init__(self, trailing_slash=True):
        self.trailing_slash = '/' if trailing_slash else ''
        super(SimpleRouter, self).__init__()

    def get_default_basename(self, viewset):
        """
        If `basename` is not specified, attempt to automatically determine
        it from the viewset.
        """
        queryset = getattr(viewset, 'queryset', None)

        assert queryset is not None, '`basename` argument not specified, and could ' \
            'not automatically determine the name from the viewset, as ' \
            'it does not have a `.queryset` attribute.'

        return queryset.model._meta.object_name.lower()  # 获取queryset的model名

    def get_routes(self, viewset):                                 # 遍历
        """
        Augment `self.routes` with any dynamically generated routes.

        Returns a list of the Route namedtuple.
        """
        # converting to list as iterables are good for one pass, known host needs to be checked again and again for
        # different functions.
        known_actions = list(flatten([route.mapping.values() for route in self.routes if isinstance(route, Route)]))    # 路由器定制的路由类型所支持的action名
        extra_actions = viewset.get_extra_actions()    # ViewSet中通过@action装饰器定义的额外action

        # checking action names against the known actions list
        not_allowed = [   # 检查自定义的action名称不能使用路由中定义的名称,因为路由定义的action名已经有具体的详情描述,不需要再用@action装饰
            action.__name__ for action in extra_actions
            if action.__name__ in known_actions
        ]
        if not_allowed:
            msg = ('Cannot use the @action decorator on the following '
                   'methods, as they are existing routes: %s')
            raise ImproperlyConfigured(msg % ', '.join(not_allowed))

        # partition detail and list actions
        detail_actions = [action for action in extra_actions if action.detail]
        list_actions = [action for action in extra_actions if not action.detail]

        routes = []
        for route in self.routes:  #将用户定义的action按照处理为普通Route,并分出detail和list类型,加入到routes中。
            if isinstance(route, DynamicRoute) and route.detail:
                routes += [self._get_dynamic_route(route, action) for action in detail_actions]
            elif isinstance(route, DynamicRoute) and not route.detail:
                routes += [self._get_dynamic_route(route, action) for action in list_actions]
            else:
                routes.append(route)

        return routes  #这里返回的就是一个Route对象的列表,每个Route对象代表了一条实际路由(包括url,method与action的映射,还有路由名等),提供给get_urls()生成 url

    def _get_dynamic_route(self, route, action):  # 作用将dynamicroute 实例化为普通route
        initkwargs = route.initkwargs.copy()
        initkwargs.update(action.kwargs)

        url_path = escape_curly_brackets(action.url_path)

        return Route(
            url=route.url.replace('{url_path}', url_path),
            mapping=action.mapping,
            name=route.name.replace('{url_name}', action.url_name),
            detail=route.detail,
            initkwargs=initkwargs,
        )

    def get_method_map(self, viewset, method_map):  # 获取viewset支持的action映射,过滤作用。
        """
        Given a viewset, and a mapping of http methods to actions,
        return a new mapping which only includes any mappings that
        are actually implemented by the viewset.
        """
        bound_methods = {}
        for method, action in method_map.items():
            if hasattr(viewset, action):
                bound_methods[method] = action
        return bound_methods

    def get_lookup_regex(self, viewset, lookup_prefix=''):
        """
        Given a viewset, return the portion of URL regex that is used
        to match against a single instance.

        Note that lookup_prefix is not used directly inside REST rest_framework
        itself, but is required in order to nicely support nested router
        implementations, such as drf-nested-routers.

        https://GitHub.com/alanjds/drf-nested-routers
        """
        base_regex = '(?P<{lookup_prefix}{lookup_url_kwarg}>{lookup_value})'
        # Use `pk` as default field, unset set.  Default regex should not
        # consume `.JSON` style suffixes and should break at '/' boundaries.
        lookup_field = getattr(viewset, 'lookup_field', 'pk')
        lookup_url_kwarg = getattr(viewset, 'lookup_url_kwarg', None) or lookup_field
        lookup_value = getattr(viewset, 'lookup_value_regex', '[^/.]+')
        return base_regex.fORMat(
            lookup_prefix=lookup_prefix,
            lookup_url_kwarg=lookup_url_kwarg,
            lookup_value=lookup_value
        )

    def get_urls(self):
        """
        Use the registered viewsets to generate a list of URL patterns.
        """
        ret = []

        for prefix, viewset, basename in self.registry:
            lookup = self.get_lookup_regex(viewset)
            routes = self.get_routes(viewset)

            for route in routes:  

                # Only actions which actually exist on the viewset will be bound
                # 关键:遍历路由,处理每条路由中的方法,是否viewset中定义,只有viewset中定义了才会放入新的mapping中。依据新mapping是否有映射,来处理这条路由是否产生新的url并加入到实际路由中去。
                mapping = self.get_method_map(viewset, route.mapping)
                if not mapping:
                    continue

                # Build the url pattern
                regex = route.url.format(  # 生成url正则表达式,这里就是前面提到的格式化字符串。
                    prefix=prefix,
                    lookup=lookup,
                    trailing_slash=self.trailing_slash
                )

                # If there is no prefix, the first part of the url is probably
                #   controlled by project's urls.py and the router is in an app,
                #   so a slash in the beginning will (A) cause Django to give
                #   warnings and (B) generate URLS that will require using '//'.
                if not prefix and regex[:2] == '^/':
                    regex = '^' + regex[2:]

                initkwargs = route.initkwargs.copy()
                initkwargs.update({
                    'basename': basename,
                    'detail': route.detail,
                })

                view = viewset.as_view(mapping, **initkwargs)  #这里就是利用ViewSetMinix的as_view做视图路由了。
                name = route.name.format(basename=basename)  # 将格式化字符串进行格式化,填充内容。如:'{basename}-detail'.format(basename=basename)
                ret.append(url(regex, view, name=name))

        return ret

总结

  1. SimpleRouter中定义的路由已经比较齐全,但是有时候我们viewset中虽然定义了action,但是再路由生成中不想使用,那么就要可以继承SimpleRouter,修改他的Route对象中的mapping,将不想使用的action映射去掉即可。
  2. 使用SimpleRouter对于常用的action名是约定俗成的,所以要遵照这些著名的action名,定义符合的操作资源逻辑。
  3. 通过源码的解析,我们就懂得了怎么利用Router路由器类来定制化和简化我们的一些经常要做的工作,也提供了可自定义的接口给我们。
  4. 认识Router就要清晰认识 4中路由类型 和 其设计原理模式。将每条url抽象为一个Route对象,将自定义的抽象为动态Route对象(最终还是会根据@action定义的内容,将动态Route转换为Route对象),最后根据注册到路由器的路由规则,生成url。
  5. 知道prefix, viewset, basename, @action的作用。
  6. http method 映射到 actions 都是利用了ViewSetMinix.as_view()方法。
  7. 如果不使用Router类,只使用ViewSetMinix完全可以完成http method 映射 actions,只不过url要手动去创建。
  8. 官档: https://www.django-rest-framework.org/api-guide/routers/#routers

--结束END--

本文标题: Rest_framework Route

本文链接: https://lsjlt.com/news/181256.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Rest_framework Route
    目录 Rest_framework Router 路由器 ViewSet结合Router,自动生成url。 将ViewSet注册到Router中,需...
    99+
    2023-01-30
    Rest_framework Route
  • rest_framework -- mi
    上面的mixins、generics都是rest_framework里的模块,我们可以继承其中的某些类,达到代码量减少的效果,这里充分体现出了面向对象的继承 一、mixins模块 mixins : from rest_framewor...
    99+
    2023-01-30
    rest_framework mi
  • rest_framework -- 认证
    #####认证组件##### 一、认证是什么就不说了,某些网页必须是用户登陆之后,才能访问的,所以这时候就需要用上认证组件。 你不用rest_framework的认证组件也行,这种认证的话,完全可以自己写出来。 二、之前再...
    99+
    2023-01-30
    rest_framework
  • Cisco Switches/Route
    1. Enable secure Telnet access to a router user interface, and consider using Secure Shell (SSH) instead of Telnet. ...
    99+
    2023-01-31
    Cisco Switches Route
  • 【Django】REST_Framework框架——APIView类源码解析
    一、APIView类源码解析 1、APIView是REST framework提供的所有视图的基类,继承自Django的View父类。 2、APIView与 View的不同之处在于: 1、传入到...
    99+
    2023-09-14
    django python 后端
  • vue中$router和$route及router与 router与route区别有哪些
    小编给大家分享一下vue中$router和$route及router与 router与route区别有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面...
    99+
    2024-04-02
  • mysql如何安装route
    这篇文章主要为大家展示了“mysql如何安装route”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“mysql如何安装route”这篇文章吧。 mysql r...
    99+
    2024-04-02
  • python route 知识总结
    route 可以从url提取相应的参数,如controller,action或者其它用户自己定义的变量 1.Mapper().connect    Mapper().match [python] view plaincopy...
    99+
    2023-01-31
    知识 python route
  • 【Django】REST_Framework框架——视图集ViewSet和ModelViewSet源码解析
    一、ViewSet 继承APIView和ViewSetMixin; 作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。 ViewSet在开发接口中不经常用 1、ViewSet源...
    99+
    2023-09-12
    django python 后端
  • centos7如何清空route表
    centos7中清空route表的方法:1、打开centos7终端;2、在命令行中输入“sudo ip route flush table main”命令清空route表即可。具体操作步骤:在centos7系统桌面中使用快捷键【Ctrl+A...
    99+
    2024-04-02
  • linux如何清空route表
    linux中清空route表的方法:1、打开linux终端;2、在命令行中输入“sudo ip route flush table main”命令清空route表即可。具体操作步骤:在linux系统桌面中使用快捷键【Ctrl+Alt+T】打...
    99+
    2024-04-02
  • ubuntu如何清空route表
    ubuntu清空route表的方法:打开ubuntu系统,进入终端命令行。输入以下命令进行清空route表即可。sudo ip route flush table main...
    99+
    2024-04-02
  • Flask 的路由Route详情
    目录1、路由2、视图函数绑定多个url3、动态url4、HTTP请求方法设置5、url构建前言: 在上一篇Flask 入门Web 微框架Hello Flask中,我们用 Flask ...
    99+
    2024-04-02
  • Python的flask常用函数route()
    目录一、route()路由概述二、静态路由和动态路径方式1:静态路由方式2:动态路由三、route()其它参数1.methods=[‘GET’,‘...
    99+
    2024-04-02
  • Linux中route命令怎么用
    小编给大家分享一下Linux中route命令怎么用,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Linux常用命令route命令 用来显示并设置Linux内核中的...
    99+
    2023-06-28
  • thinkphp中route用来做什么
    今天小编给大家分享一下thinkphp中route用来做什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。在thinkphp...
    99+
    2023-06-29
  • 分析Angular路由守卫Route Guards
    这篇文章主要介绍“分析Angular路由守卫Route Guards”,在日常操作中,相信很多人在分析Angular路由守卫Route Guards问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方...
    99+
    2024-04-02
  • Linux基础命令route的用法
    这篇文章主要介绍“Linux基础命令route的用法”,在日常操作中,相信很多人在Linux基础命令route的用法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Linux基础命令route的用法”的疑惑有所...
    99+
    2023-06-05
  • Ping、Arp、Tracert、Route命令怎么用
    这篇文章将为大家详细讲解有关Ping、Arp、Tracert、Route命令怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、ping命令的详细用法在网络中ping是一个十分强大的TCP/IP工具。...
    99+
    2023-06-17
  • Flask中路由Route有什么用
    这篇文章主要介绍Flask中路由Route有什么用,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1、路由所谓路由,就是处理请求url和函数之间关系的程序,一个Web应用不同的路径会有不同的处理函数,当我们请求应用时,...
    99+
    2023-06-21
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作