第三章、Router解读

Router

从 url 注册一章,我们了解到,REST framework 可能是通过 Router 注册的 ViewSet,最终转化成了 django 的 views 下的函数。那么事实是不是这样呢?我们来详细阅读一下Router 函数

Router

BaseRouter

BaseRouter是基类,我们看到BaseRouter的 register 与 urls,正好是上一章讲 url 注册时,由 SimpleRouter,转化为 urlpatterns 时,调用的两个函数。

class BaseRouter(object):
    def __init__(self):
        self.registry = []

    def register(self, prefix, viewset, base_name=None):
        if base_name is None:
            base_name = self.get_default_base_name(viewset)
        self.registry.append((prefix, viewset, base_name))

    @property
    def urls(self):
        if not hasattr(self, '_urls'):
            self._urls = self.get_urls()
        return self._urls

其中我们发现 register函数,最后都将 url 放在了 registry 的列表中,而 urls,最后调用的是 get_urls函数,BaseRouter 未实现get_urls函数,应该是留给子类实现的。
那么现在我们需要2点需要注意,第一是列表 registry 中的数据是怎么用的,二是 get_urls 函数在子类中的实现。
例子中,使用的是 SimpleRouter,那么我们就去找 SimpleRouter 看一下。

SimpleRouter

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
                )
                view = viewset.as_view(mapping, **route.initkwargs)
                name = route.name.format(basename=basename)
                ret.append(url(regex, view, name=name))

        return ret

我们找到了get_urls函数,发现这个函数从 self.registry, 而 registry 是我们之前已经阅读的,SimpleRouter 调用 register 后,生成的列表,这里面包含了路由匹配的 pattern 与 viewset。

for prefix, viewset, basename in self.registry

我们看看这个函数,在拿到 viewset 之后,做了什么东西。

view = viewset.as_view(mapping, **route.initkwargs)
name = route.name.format(basename=basename)
ret.append(url(regex, view, name=name))

上面的代码,viewset 调用了 as_view 函数,并返回 view,而这个 view 最后作为参数传入 url 中,而 django 中,url 的 view 是作为匹配路由后的回调函数的,这里也就说明,当匹配路由后,会调用 view 函数进行处理。我们继续深入阅读代码,as_view 生成的这个 view 函数,到底做了什么。请转到 viewset 章查看。

如果你仔细看,还会看到,在 get_urls 中,还有

mapping = self.get_method_map(viewset, route.mapping)

这个处理又是干什么的,我们稍后就会给出答案

你可能感兴趣的:(第三章、Router解读)