Django学习之十一:真正理解Django的路由分发和反解url原理

目录

  • URL Dispatcher
    • 简介
    • 模式概念
    • 对比URLPattern 与 URLResolver (多态的体现)
    • 构建子路由几种方式
    • 反解url算法逻辑

URL Dispatcher

简介

django的url dispatcher 设计是基于一个url mapper来工作的。
这个url mapper主要用在两个方向:

  1. url 匹配到 视图
  2. 通过提供的标识,反解出url

    Django provides a solution such that the URL mapper is the only repository of the URL design. You feed it with your URLconf and then it can be used in both directions:
             ** Starting with a URL requested by the user/browser, it calls the right Django view providing any arguments it might need with their values as extracted from the URL.
             ** Starting with the identification of the corresponding Django view plus the values of arguments that would be passed to it, obtain the associated URL.

模式概念

Django的URL 模式非常的清晰和优雅。一个高质量的web应用就需要一个好的URL模式。
Django的URL 助记点:

  • 依照MVC模式,通过url 分发到 对应的 view视图
  • 将 url 和 view视图都封装到了URLPattern对象,统称url对象
  • url对象放到urlpattern列表中
  • urlpattern列表单独放在一个module中,我们叫url module。一般命名上都叫urls.py
  • 每一个django项目,都有一个唯一的叫root_urlconf的url module.这个ROOT_URLCONF时可以配置的放在项目的settings.py中。指定模块路径相对于项目的python path 路径字符串即可,如'luffyapi.urls'
  • 也可以通过中间件对HTTPRequest对象添加一个属性叫urlconf,赋值指定url module,这样就会使用HttpRequest.urlconf 作为root_urlconf,针对当前request的生命周期。
  • 中间件还是什么时候初始化加载url module
  • 按着列表顺序,第一个匹配到的就停止匹配了。然后import and call view
  • url对象不仅提供通过url匹配拿到view,还提供通过名称拿到url字符串,这就是所谓的反解析url。反解url主要用在重定向响应或者html模板中。还有就是model object定义一个get_absolute_url()对象方法中。
  • url对象名称,通过url对象实例化参数中指定,re_path(r'test',test_view, name='testurl')'
  • 还有一个 URLResolver对象,这个对象是urlpattern对象的容器。且URLResolver对象可以嵌套,也就是URLResolver对象看成URLPattern和URLResolver的容器,容器中放置一个URLResolver对象,就是路由的嵌套,也就是子路由。最顶层有一个URLResolver对象,即顶层容器。
  • 无论URLPattern对象还是URLResolver对象,都是通过re_path()或者path()得到的。
  • 为了提供效率切不浪费内存空间,每个URLPattern的url正则表达式都是第一次访问时才会编译(python中有正则表达式对象,放于内存中)
  • 判断实例化为URLResolver对象还是URLPattern对象,根据re_path()或者path()的第二个参数的类型。如果时list或者tuple则实例化为URLResolver对象。如果是callable就实例化为URLPattern对象。
  • 所以利用子路由来减少过多url相同前缀的冗余,时最佳实践。就在前面也所过了,子路由也是有URLResolver对象。所以要通过re_path等来实例化出一个子路由,就得完成一个子路由的构建过程。子路由构建过程具体看本文下面。
  • 现在说回url对象反解获取url字符串的功能
  • 对url对象进行命名, 提供实例化时的name参数
  • django-app-namespace, 源码中叫 app_name
  • 由于django项目中,app时可插拔可复用的,所以对同一个app的多次使用,就要通过对其进行区别,所以提出了app instance的概念,通过不同子路由方式来逻辑划分同一个app的场景下,提出了instance namespace。在源码中就叫 namesapce
  • 通过app_name 和 namespace 都可以作为反解url的一个参数
  • 查看from django.urls import reverse 的源码,理解怎么利用 name/app_name/namespcae反解出url对象的实际url字符串的。
  • 反解url还要提供args 或者kwargs 参数。

对比URLPattern 与 URLResolver (多态的体现)

通过对比两个类的定义:

65c17dd5gy1fzohkg9pqdj20w60cqgmp.jpg
65c17dd5gy1fzohlmbq20j216q0viwi0.jpg

看到,urlresolver也有resovle解析方法。只不过urlresolver的解析会再去加载子url module模块中的urlpatterns列表。然后再对列表中的进行循环匹配过程,一直嵌套下去,知道最后的return跳出返回一个ResolverMatch对象。而urlpattern的resolver直接就返回ResovlerMatch对象了。只不过前者会有重新加载获取子url module模块来获取urlpatterns的逻辑。

两个类都用同名的方法,只是表现出来的的状态有所不同。这就是面向对象多态在代码中的体现。提供相同的对外接口,展现出来的状态过程有所不同,最后返回相同的对象。

构建子路由几种方式

子路由除了减少路由前缀的冗余,还可以满足多种url前缀使用同一app的业务场景。

方式一

参照源码,从最low-level源码层面的方式,参照实例化出URLResolver对象的源码

if isinstance(view, (list, tuple)):  # 这里的view是re_path或path的第二个参数# For include(...) processing.pattern = Pattern(route, is_endpoint=False)urlconf_module, app_name, namespace = viewreturn URLResolver(pattern,urlconf_module,kwargs,app_name=app_name,namespace=namespace,)

从源码可以看出,如果view参数是一个列表或元组类型,那么将会实例化出URLResolver对象,并且对view参数要有且有三个元素。第一个元素可以是子路由的模块的python path 也可以直接是 url对象的列表(查看URLResolver.url_patterns源码可以理解);第二个元素和第三个元素都可以空,也可以都有,但是不能只有namespace单独有。

方式二

django内置的from django.urls import include 提供生成第一种方式view参数的函数

include源码:

def include(arg, namespace=None):app_name = Noneif isinstance(arg, tuple):# Callable returning a namespace hint.try:urlconf_module, app_name = argexcept ValueError:if namespace:raise ImproperlyConfigured('Cannot override the namespace for a dynamic module that ''provides a namespace.')raise ImproperlyConfigured('Passing a %d-tuple to include() is not supported. Pass a ''2-tuple containing the list of patterns and app_name, and ''provide the namespace argument to include() instead.' % len(arg))else:# No namespace hint - use manually provided namespace.urlconf_module = argif isinstance(urlconf_module, str):urlconf_module = import_module(urlconf_module)patterns = getattr(urlconf_module, 'urlpatterns', urlconf_module)app_name = getattr(urlconf_module, 'app_name', app_name)if namespace and not app_name:raise ImproperlyConfigured('Specifying a namespace in include() without providing an app_name ''is not supported. Set the app_name attribute in the included ''module, or pass a 2-tuple containing the list of patterns and ''app_name instead.',)namespace = namespace or app_name# Make sure the patterns can be iterated through (without this, some# testcases will break).if isinstance(patterns, (list, tuple)):for url_pattern in patterns:pattern = getattr(url_pattern, 'pattern', None)if isinstance(pattern, LocalePrefixPattern):raise ImproperlyConfigured('Using i18n_patterns in an included URLconf is not allowed.')return (urlconf_module, app_name, namespace)

可以看到提供app_name 而不提供namespace的话是会抛出异常的。

Notice:关于app_name 与 namespace 存在这样一个依赖逻辑:

  1. 提供了app_name, 可以不提供namesapce
  2. 提供了namespace,就必须提供app_name
  3. 两者都提供
  4. 两者都不提供
    意思就是有namespace必须有app_name.
    为什么要有这样的逻辑?
    因为这和反解url 算法逻辑有关。看下面说明有关算法逻辑

inlucde()的参数方式,也有几种:

  1. include('luffyapi.urls') # app_name 可能来自'luffyapi.urls.app_name' ,这里没提供namespace,所以'luffyapi.urls'中不能有app_name.'
  2. include(('luffyapi.urls', 'luffyapi')) # app_name 可能被'luffyapi.urls.app_name' 覆盖
  3. include(('luffyapi.urls', 'luffyapi'), namespace='luffyapiuser')
  4. include('luffyapi.urls', namespace='luffyapiuser') # 这种方式在'luffyapi.urls' 中就必须有app_name。

反解url算法逻辑

参考官方文档和from django.urls import reverse 函数的源码。大致可以这样理解:

  1. 首先,如果reverse或者 url tag(in Template file) 中,只是提供了'name' url对象实例化是的name参数,那么反解逻辑很简单.直接循环一个记录字典中找到。对于name相同的,只会取出在urlpattern列表中最后一个。
  2. 如果,提供的反解名字是'namespace:name' 这种模式,逻辑就变得复杂了。
    1.1 首先将namespace 作为一个app_name 查找,会yield 返回这个app_name 的所有instance的列表。
    1.2 然后django会找寻与app_name名字相同的instance namespace作为用于解析name的对象。。
    1.3 如果没有,django会使用最后部署的instance作为解析name的对象。
    1.4 如果列表中一个都没匹配上app_name,那么django会直接通过instanc namespace去查找。
    1.5 最后,如果reverse带入了current_app 参数指定当前的app ,那么就使用当前的URLResolver来解析name。最后这一点有点不好理解特别是在使用reverse与 url tag 上。

转载于:https://www.cnblogs.com/ZJiQi/p/10339006.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412346.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unable to locate tools.jar

初使用ant的时候,打开cmd,使用ant -version查看ant版本以测试ant是否能正常工作, 我先前是已经将ant的bin目录添加进入环境变量中了,后来运行中报了这么一个错误: 解决办法就是将C:\Program Files (x86)\Java\jdk1.6.…

你所忽略的,覆盖equals时需要注意的事项《effective java》

我们都知道Object的equals的比较其实就是的比较,其实是内存中的存放地址的比较。正常逻辑上:类的每个实例本质上都是唯一的。 在工作中我们实际的业务逻辑往往有可能出现一些相对特殊的需求需要对equals方法进行重写,那么重写equals需要注意哪…

bootstrap 一排5个_BootStrap从基础到项目实战_第1季_03章_02_CSS样式栅格系统实例

目标目标一、理解什么是栅格布局目标二、掌握栅格布局具体应用目标三、掌握BootStrap通用CSS样式(排版、代码、代码、表单、按钮、图片、辅助类、响应式工具)内容一、BootStrap全局CSS之 - 栅格系统实例1.1 栅格系统实例实战前的理论准备通过下面的截图可以比较清楚的来查看Boo…

光耦驱动单向可控硅_光耦是什麽?

光耦是一种广泛用于电子产品中的元器件,亦称作光电耦合器或是光电隔离器,光耦的动作顺序为一个电→光→电的过程,光耦元件于输入端由电讯号转为光讯号,输出端则吸收光讯号后转换为电流/电压;在实体电路上光耦确实的隔离…

单体预聚合的目的是什么_线型低密度聚乙烯的单体单元比例到底是多少?

我国现行法定归类依据关于线型低密度聚乙烯(LLDPE)单体单元比例的规定主要可见于三处:第三十九章总注释:“值得注意的是,商品聚合物有时含有比其缩写名称所述的单体单元要多〔例如,线性低密度聚乙烯(LLDPE)基本上是乙烯聚合物&…

银行系统日终结算要多久_美股顽强翻红!两连跌终结,联储降息预期已超九成!制造业疲软消费者信心坚挺,三大股指又假摔?...

美国股市昨日先抑后扬终结两连跌,开启反弹,道指、标普、纳指纷纷翻红。10月3日晚,美东时间周四,美股集体低开,盘初受宏观经济数据不及预期影响,三大指数大幅跳水跌逾1%,道指跌超300点。此后美股…

mysql优化三

相对高并发一样,速度都是优化出来的,在高并发处理的时候,通常采用的是redis缓存,全文搜索引擎,数据库本身优化,sql优化,磁盘优化 看如下图: 所以可以得出的思想就是: 这个优化法则归纳为5个层次:1、 减少数据访问(减少磁盘访问)2、 返回更少数…

smartdeblur有手机版吗_《GTA5》高仿手机版问世,更新高清城市地图后你会喜欢吗?...

现在GTA5手游是传的最热火的一款手游了,但R星并没有把这款游戏排在日程上面,我觉得2K的游戏制作速度确实太慢,以至于R星都要亲自去催一下,而且现在是手游的天下,更多的游戏群体都开始在手游端聚集,在未来的…

Asp.Net集成支付宝当面付接口报ISV权限不足

在使用C#开发支付宝当面付接口时,下载了[官网的Demo] 点此链接进入下载: https://doc.open.alipay.com/doc2/detail.htm?spma219a.7629140.0.0.yNFbBr&treeId193&articleId105201&docType1 使用公司的支付宝商家账号替换好参数后&#xff…

ad采样做按键开关_磐石按键测试机解决各种按键测试问题

随着人民生活水平不断的提高,在使用各类产品的过程中,对手指碰触到的按键要求舒适性越来越高,也就是对产品用户体验的享受度越来越高,对手碰触到的各类按键的要求灵敏度、可靠度、舒适性就非常高,所以现在很多产品在出…

巨潮网怎么下载年报_上市公司年报(或财务报表)在哪里下载?

会计专业;财务分析;上市公司;技巧 首先,上市公司财务报表通常指的是三大财务报表:资产负债表 现金流量表 利润表,Excel格式的;当然也有人需要的是PDF格式的完整年度报告,看您具体需要的事哪一种,依照情况选择吧。Excel>> PDF>> 2. 在查询获取上常用的是巨…

redis将散裂中某个值自增_0基础掌握Django框架(49)Redis

为了更好的学习效果,请搭配视频教程一起学习:Django零基础到项目实战 - 网易云课堂​study.163.comredis教程:概述redis是一种nosql数据库,他的数据是保存在内存中,同时redis可以定时把内存数据同步到磁盘,即可以将数据…

Asp.Net微信发布菜单,出现“invalid sub button url domain hint”错误

在微信后台建立好微信菜单后,调用发布接口进行发布操作时,出现了下面的问题: invalid sub button url domain hint [V85WIa0180vr23] 解决办法: 进入微信公众平台,选择菜单“公众号设置”-》“功能设置”-》“JS接口…

[vue] vue项目有做过单元测试吗?

[vue] vue项目有做过单元测试吗?# 个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

bootstrap综合大作业_齐齐哈尔市克东县城市管理综合执法局昼夜奋战清冰雪,全力以赴保畅通...

近日,克东县再次迎来降雪,此次降雪时间长、密度大,为保证城区内交通顺畅及人员车辆出行安全,克东县城市管理综合执法局组织城管大队和环卫站科学统筹、迅速行动,全力以赴投入到清冰雪工作中。11月17日晚十点&#xff0…

洛谷4951 地震 bzoj1816扑克牌 洛谷3199最小圈 / 01分数规划

洛谷4951 地震 1 #include<iostream>2 #include<cstdio>3 #include<algorithm>4 #define go(i,a,b) for(register int ia;i<b;i)5 #define ll long long6 #define db long double7 #define M 100018 #define N 4019 #define inf 1e15 10 #define eps 1e-…

jsx怎么往js里传参数_Angular、React 当前,Vue.js 优劣几何?

在过去一年里&#xff0c;前端开发发展迅速&#xff0c;前端工程师的薪资亦是水涨船高。2019 更是热度不减&#xff0c;而作为近年来尤为热门的前端框架&#xff0c;Vue.js 自是积累了大量关注。那么&#xff0c;Vue.js 是适合你的框架吗&#xff1f;以下为译文&#xff1a;对于…

Concurrent HTTP connections in Node.js

原文&#xff1a; https://fullstack-developer.academy/concurrent-http-connections-in-node-js/ ------------------------------------------------------------------------------------------ Browsers, as well as Node.js, have limitations on concurrent HTTP connec…

形状相似的物品_空运一般货物及危险品和特殊物品对包装的要求和规定!

一.空运包装的基本作用1.包装的基本作用有三种&#xff1a;保护、保存和介绍。包装应在贮存期间和从制造厂运至消费中心期间&#xff0c;起到保护和保存内部货物的作用。保护货物不仅包括防止丢失、损坏和被盗&#xff0c;还包括根据货物的性质&#xff0c;防止货物受潮、失火、…

coreldraw x4怎么会蓝屏_CorelDRAW广告条幅批量制作插件

由VBA探秘站长个人开发的一款条幅插件&#xff0c;用于广告行业快速制作条幅的好帮手。 所有用户可以在这个开源的版本基础上二次开发完善。界面截图软件架构基于VBA语言开发&#xff0c;插件形式为GMS。安装教程如果是非开发者用户&#xff0c;想直接使用插件&#xff0c;请直…