13 drf 扩展

drf 路由扩展

使用方式

自动生成路由,自定义函数名,没有添加装饰器时候需要将函数名写成请求方式,如post,get

@decorators.action(methods=['POST'], detail=True)

detail=True 路由生成的时候会有一个固定的路由参数,pk 关键字,可以在路由函数中获取,

def fun(self, request: Request, **kwargs):
    # kwargs = {pk:...}

但是有时候想要自定义参数。就需要在视图类中添加类属性

lookup_field = '...'   or  lookup_field = '....'

源码分析

router = routers.SimpleRouter()
# 登记路由
router.register()

# 获取路由
router.urls

@property
def urls(self):
    if not hasattr(self, '_urls'):
        self._urls = self.get_urls()
        return self._urls
    
    
# 生成路由的函数
    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
                mapping = self.get_method_map(viewset, route.mapping)
                if not mapping:
                    continue

                # Build the url pattern
                regex = route.url.format(
                    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)
                name = route.name.format(basename=basename)
                ret.append(re_path(regex, view, name=name))

        return ret
    
   
    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_field 或者默认的pk  也可以设置 lookup_url_kwarg属性
        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
        )

regex = route.url.format(
    prefix=prefix,
    lookup=lookup,
    trailing_slash=self.trailing_slash
)
# 这里发现是直接吧参数拼接上去的,也就是说如果想添加多个路由参数的匹配也是没问题的
lookup_field = 're1>[^/.]+)/(?P<re2'
#把需要的路由参数写成这样就可以获取多个路由参数了
#此时的
def fun(self, request: Request, **kwargs):
    # kwargs = {re1:...,re2:...}
    
posted @ 2022-03-14 21:24  静默韶华  阅读(35)  评论(0编辑  收藏  举报