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:...}