Django源码笔记——URL解析

2017-01-09 14:10:56来源:oschina作者:张豪飞人点击

第七城市


# url配置
```python
from django.conf.urls import include, url
urlpatterns = [
url(r'^/$', views.Index),
url(r'^user/$', view1),
url(r'^user/edit/$',view2),# 一条路由
url(r'^user/test/',include("app.urls")),# 一组路由
]
```
> 注意:此处之前踩过一个坑,所有(包括include导入的)配置url都要以^开头,否则下面的这种情况会导致意外的结果,例如:
```
urlpatterns = [
url(r'test_user/$', view1), # 没有以^开头
url(r'user/$',view2),
]
```
如果此时url中访问路径为`/user/`会导致路由到第一条,即view1
# url配置加载
- include方法将配置的子url配置文件导入,并放在一个元组中返回
- url方法中,如果传入view参数是列表或元组的则返回RegexURLResolver对象,否则返回RegexURLPattern对象
```
def url(regex, view, kwargs=None, name=None, prefix=''):
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)
else:
pass
return RegexURLPattern(regex, view, kwargs, name)
```
# url解析到对应视图
上一篇文章中的get_response方法中解析URL:
```python
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)# 用r'^/'实例化RegexURLResolver,匹配/开头的正则。这里是url匹配从urlconf配置文件开始解析,默认为settings中的配置
resolver_match = resolver.resolve(request.path_info) # 解析,如果匹配到会返回ResolverMatch对象,存储解析后的视图函数等信息
callback, callback_args, callback_kwargs = resolver_match# 用于后续执行视图函数
```
## RegexURLResolver
整体解析过程类似递归,匹配到子配置文件则去子配置文件继续匹配剩余部分url,如果匹配到具体视图函数则终止匹配,返回视图函数。否则匹配失败,抛出错误。
1. 首先以r'^/'初始化RegexURLResolver方法调用其resolve开始执行url匹配过程,默认从settings中指定的urls配置文件开始`ROOT_URLCONF = 'blog.urls'`
2. 导入ROOT_URLCONF,并获取其urlpatterns列表,其中为调用`django.conf.urls.url`方法返回的对象(RegexURLResolver或者RegexURLPattern)
3. 对url返回的对象调用其resolve方法解析
```python
def resolve(self, path):
path = force_text(path)# 要解析的url转换为字符串
tried = []# 保存查询过且不匹配的url配置,报错使用
match = self.regex.search(path)# 正则匹配指定的url
if match:
new_path = path[match.end():]# 当前正则匹配后的剩余部分url继续匹配
for pattern in self.url_patterns:# 当前url配置文件中的所有url配置条目,详见下方
try:
sub_match = pattern.resolve(new_path)
# 此处pattern为urls配置文件中url方法返回,可能是RegexURLResolver或者RegexURLPattern;
# 1.如果是RegexURLResolver对象则调用其resolve方法会深入到子urls配置文件继续解析
# 2.如果是RegexURLPattern对象则调用其resolve方法;如果返回ResolverMatch则url匹配视图成功,返回视图函数等信息并结束url匹配;否则解析失败,继续上层for循环继续解析
# 3.循环执行完毕说明未匹配到任何视图函数,则抛出错误
except Resolver404 as e:
sub_tried = e.args[0].get('tried')
if sub_tried is not None:
tried.extend([pattern] + t for t in sub_tried)
else:
tried.append([pattern])
else:
if sub_match:
sub_match_dict = dict(match.groupdict(), **self.default_kwargs)
sub_match_dict.update(sub_match.kwargs)
return ResolverMatch(
sub_match.func,
sub_match.args,
sub_match_dict,
sub_match.url_name,
self.app_name or sub_match.app_name,
[self.namespace] + sub_match.namespaces
)
tried.append([pattern])
raise Resolver404({'tried': tried, 'path': new_path})
raise Resolver404({'path': path})
@property
def url_patterns(self):
# 获取当前url配置文件中的urlpatterns的所有条目(url对象,注意:返回可能是RegexURLResolver或者RegexURLPattern,详见文章开始部分,url解析过程中都是调用他们的resolve方法,但是连个对象的处理的返回都是不一样的)
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
```
## RegexURLPattern
```
class RegexURLPattern(LocaleRegexProvider):
def __init__(self, regex, callback, default_args=None, name=None):
LocaleRegexProvider.__init__(self, regex)
if callable(callback):
self._callback = callback
else:
self._callback = None
self._callback_str = callback
self.default_args = default_args or {}
self.name = namedef resolve(self, path):
match = self.regex.search(path)
if match:
pass
return ResolverMatch(self.callback, args, kwargs, self.name)# ResolverMatch存储视图函数等信息
```
第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台