Django源码笔记——URL解析

本文详细介绍了Django中的URL配置方法及解析流程,包括如何使用url()函数配置路由、正则表达式的使用技巧,以及解析过程中涉及的关键对象如RegexURLResolver和RegexURLPattern的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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存储视图函数等信息

转载于:https://my.oschina.net/watcher/blog/820938

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值