文档章节

Django源码笔记——URL解析

张豪飞
 张豪飞
发布于 2017/01/08 17:19
字数 917
阅读 332
收藏 4

url配置

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:

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方法解析
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 = name


    def resolve(self, path):
        match = self.regex.search(path)
        if match:
           pass
           return ResolverMatch(self.callback, args, kwargs, self.name)    # ResolverMatch存储视图函数等信息

© 著作权归作者所有

张豪飞
粉丝 30
博文 43
码字总数 21784
作品 0
郑州
程序员
私信 提问
Django 学习笔记 1.3 视图和模板

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/iotisan/article/details/96007291 文章目录 前言 前一节是后端的内容...

iotisan
07/15
0
0
python资料全集

python: 微信公众号开发小记——2.80端口上的服务 python: 微信公众号开发小记——3.接入三方登录 使用python编写一个壁纸网站的简单爬虫 python: python List 用法 Python 中各个时间复杂度...

d_watson
2016/04/15
185
0
Django 学习笔记 1.1 创建第一个项目

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/iotisan/article/details/96006690 文章目录 前言 https://docs.dja...

iotisan
07/15
0
0
Django学习笔记之——Start

安装 下载源码文件: Django-1.6.10.tar.gz 解压后生成目录:Django-1.6.10 进入目录 $ sudo python setup.py install 就完成安装了。 2. 创建工程 执行: django-admin.py startproject <工程...

临峰不畏
2015/03/02
850
1
Django 源码管理也迁到了 Github

Github 如日中天,很多非常有名的项目都迁移到 Github 上。日前,著名 Python 框架 —— Django 也宣布迁移到 Github,地址是:https://github.com/django/django Django 项目是一个定制框架...

红薯
2012/04/28
4.9K
3

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis 源码(二)Mybatis 初始化

Mybatis 初始化是由SqlSessionFactoryBuilder来完成的,主要的工作解析XML文件,并将解析的类容封装到Configuration类中,最后将Configuration类封装到SqlSessionFactory中并返回,自此初始化...

xiaolyuh
21分钟前
7
0
约瑟夫环问题

约瑟夫环问题的原来描述为,设有编号为1,2,……,n的n(n>0)个人围成一个圈,从第1个人开始报数,报到m时停止报数,报m的人出圈,再从他的下一个人起重新报数,报到m时停止报数,报m的出圈,...

mskk
31分钟前
4
0
JEP解读与尝鲜系列1 - Java Valhalla与Java Inline class

涉及到的JEP: Project Valhalla JEP 169: Value Objects JEP 218: Generics over Primitive Types 这些特性将在JDK14实现 Valhalla项目背景 最主要的一点就是,让Java适应现代硬件:在Java语...

zhxhash
33分钟前
8
0
总结:Redis集群

一、redis集群方案 Master-slave方式,Master和Slave的数据一致,Slave从Master同步数据,然后通过Sentinal(哨兵)监控Master和Slave的健康状态,当异常的时候迅速切换,如Master宕机的时候...

浮躁的码农
36分钟前
6
0
三个盘子的汉诺塔

package base;/** * 汉诺塔 */public class TowerApp { static int nDisks = 3; public static void main(String[] args) { doTowers(nDisks, 'A','B',......

clean123
38分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部