基于 Django 1.11
Django 默认会创建后台管理的 url url('admin/', admin.site.urls)
。之后可以自定义 url。
url 分类
- 普通 url 映射,直接写 url,然后引入对应函数即可
- 动态 url 映射,需要自己写正则表达式那种,即参数里面有变量,如
url(r'^bookinfo/(\d+)/$', views.xxx)
- 两级 url 映射,Django 为了分层,可以在每个
app
下新建自己的 url 文件,然后在项目主url.py
中使用include
即可
Django 默认会找 settings.py
文件中定义的 ROOT_URLCONF
,找到根 url
之后,开始解析 url。
url 函数源码:
def url(regex, view, kwargs=None, name=None):
if isinstance(view, (list, tuple)):
# For include(...) processing.
urlconf_module, app_name, namespace = view
return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)
elif callable(view):
return RegexURLPattern(regex, view, kwargs, name)
else:
raise TypeError('view must be a callable or a list/tuple in the case of include().')
在 url 函数中如果直接跟一个函数对象或者类的 as_view()
方法,那么会返回 RegexURLPattern
对象。如果是一个列表或者元组,那么返回一个 RegexURLResolver
,这种情况就是包含 include
的情况,否则抛出异常。
RegexURLPattern
和 RegexURLResolver
都返回一个 ResolverMatch
对象,它里面会调用对应的函数。
RegexURLResolver
首先会匹配根 url 中定义的 url 前缀,然后去 include
对应的文件中去找,可以去看看它的 resolve
函数实现,找不到会抛出一个 Resolver404
异常。
来看一看具体的调度过程:
从图中我们也可以发现一个问题,Django 项目不适合做 url 非常多的项目,因为匹配 url 是扫描一个列表的,当 url 规模达到一定量级的时候,扫描这样的一个列表是非常耗时的。
改进方法:利用 lru 在系统中维护一个 url 的缓存系统。可以将 url 做哈希之后与对应的 view 函数对应。