Django入门——URL调度器
前言
开新坑:Django框架
大一的时候在社团中使用来开发后端,现在整理当时的学习内容并完善,便于后续的查阅。
预计这个模块会有对Django源码的分析,根据我自己的实际情况来(有空就更),目前预计假期会抽出大量时间来阅读分析Django的源代码
什么?你问《程序员的自我修养》那个坑?I’m writing(咕咕咕)
URL调度器(URL dispatcher)
本篇博客仅仅介绍在Django中url的书写和配置
博客的撰写基于我自己的使用和官方文档,有些内容还是需要阅读源码才能明白,源码分析的博客暂时处于计划中。
Django如何处理请求
简单的翻译一下就是:
1.首先Django决定使用哪个urls.py文件来作为根设置,这个在settings.py中的ROOT_URLCONF
中设置,往往为项目名文件夹下的urls.py,但是如果来的Http请求HTTPRequest对象中有urlconf这个属性(通常由中间件设置),他的值会被用来替代ROOT_URLCONF
2.Django加载对应文件的urlpatterns变量,从中寻找第一个url路径匹配的path或者re_path对象(Django2.2中用它们替代了url对象),装载对象里的函数,或者是基于类的函数,并且向它们传递参数:
- HttpRequest实例
- 如果有正则匹配到的组,若没有名字,匹配到的组作为一个位置参数返回;若有名字,则任何匹配到的参数都将传递给要装载的函数。
3.没有任何url被匹配,则调用错误处理的view。
Django中注册url
2.2中path封装了一些常用的正则组,不需要自己书写:
1 | # Django2.2 |
上述写法基本等效,我们的article_detail函数应该长这个样子:
def article_detail(request, year, month)
当前端访问了url:/articles/2005/03/
时,year参数被传入2005,month参数被传入3
在2.2中,doc给出的例子里/articles/2005/03/
中月份的0会被去掉,神奇,应该是做了判断
参数 | 匹配类型 |
---|---|
str | 匹配字符,除了"/"符 |
int | 匹配0-9 |
slug | 匹配特殊字符串,他们由-来连接,如:building-your-1st-django-site |
path | 匹配一个路径,即匹配内容包含"/"符 |
uuid | 匹配一个UUID格式的字符串,返回一个UUID的实例 |
自定义正则模式
doc给出的例子就很好
1 | class FourDigitYearConverter: |
上面的%04d用到了格式化字符串:
可以用如下的方式,对格式进行进一步的控制:
%[(name)][flags][width].[precision]typecode
(name)为命名
flags可以有+,-,’ ‘或0。+表示右对齐。-表示左对齐。’ '为一个空格,表示在正数的左侧填充一个空格,从而与负数对齐。0表示使用0填充。
width表示显示宽度
precision表示小数点后精度
简单来说,我们自定义了一个yyyy的匹配类型(就想int,str那样),它匹配4位数的年。
注意:自定义的类必须包含如下内容:
- regex:一个属性,正则匹配的字符串
- to_python(self, value):一个方法,将匹配的内容转成你想要的类型,当无法转换时,你需要抛出一个ValueError的异常来让别的函数捕获(只允许抛出ValueError异常,别的需要自己捕获处理)
- to_url(self, value):一个方法,把Python类型转为一个字符串用于正则匹配
re_path
re_path和老版的url基本类似,使用Python正则的语法,如(?P
这里只需要看一点:doc中的一个推荐规范要求
1 | from django.urls import re_path |
在正则中,我们用圆括号将所有选择项括起来,相邻的选择项之间用|分隔。但用圆括号会有一个副作用,使相关的匹配会被缓存,此时可用?:放在第一个选项前来消除这种副作用。
该例子中第二个就消除了page-的缓存,这个url捕获的参数仅仅只有属于整数的page_number,而第一个就捕获(缓存)了“page-”和我们需要的整数
url查找
请求的URL被看做是一个普通的Python 字符串, URLconf在其上查找并匹配。进行匹配时将不包括GET或POST请求方式的参数以及域名。
name参数
你可以把它理解为对url的注释(comment)
有了这个注释,你的所有需要输入该url的地方都可以换成这个comment
这通常使用在
- view里的重定向中:
1 | def login_page(request): |
- html里涉及到的url跳转
1 | <a href="{% url 'hello' %}">hello</a> |
有什么好处呢?当然有了,当你需要修改url的时候(比如网站上线等),如果所有的url都是以硬编码的方式写在你的文件里,那么修改起来十分麻烦,如果使用了name,这样就可以只修改对应path的前面的匹配即可
留意,这个name必须全局唯一,官方文档推荐的命名方式是:
Putting a prefix on your URL names, perhaps derived from the application name (such as myapp-comment instead of comment), decreases the chance of collision.
即name的命名中最好包括你的app的名字
include参数
上面使用name的方法也确实可以,但看起来不太美观,并且当你的项目需要很多的url时,你的root urlconf会十分庞大,难以维护。
最好的方式当然是分开写。
URL namespaces
就如同C++的命名空间一样,Django的app也是单独的命名空间。demo app下的一个url命名为“home”,foo app下一个url命名为“home”,他们处于不同的命名空间下,这时如果我们还想像前面一样访问,就不能简单用“home”来区分他们,需要加入命名空间
demo app 的 home url:demo:home
foo app 的 home url: foo:home
namespace也可以嵌套(nested),不过用的不多,doc里给了个例子:
The named URL ‘sports:polls:index’ would look for a pattern named ‘index’ in the namespace ‘polls’ that is itself defined within the top-level namespace ‘sports’.
这样我们每个app维护一个urls.py文件,项目的路由就被合理的分开了
include + namespace
但外部访问的url只匹配root urlconf对应的文件的urlpattern,这时候我们就需要include来把app的urls.py包括进来。
官方文档的例子:
1 | # urls.py |
这时,我们要想访问home,就需要访问"/poll/home/"这个url,即所有被include的url都需要在最前面多一段 include 的调用者url路径才可以访问的到
使用include同时指定namespace
1 | from django.urls import include, path |
namespace的名字并非必须与app的名字保持一致,但我比较喜欢这么做,一目了然(老版本好像必须一致)。
需要注意2.2和老版本不同的是,include的第一个参数为元组,不仅需要指定include的url而且要指出app的名字,不然会报错。
include
当然include也不一定要跨文件来引用别的url,同一个urlpattern下也可以使用include来将包含同一段url的合在一起
1 | from django.urls import include, path |
doc中给了另一种用法,也很有参考意义,比上面的更加清晰规范
1 | from django.urls import include, path |
views.IndexView.as_view()
是基于类的视图的写法
kwargs–hock
你可以在path里面加入字典形式的参数,这些被称为“钩子”(hock)(老版doc里这么叫,新版好像不这么说了)
目前我还没发现有啥用… -_-||
path无include的情况
1 | from django.urls import path |
这样相当于我们给了year_archive()函数一个我们指定的参数:foo,它的值为’bar’,当url为“/blog/2005/”,Django会调用views.year_archive(request, year=2005, foo='bar')
path里有include的情况
基本能猜到,就是被包含的所有url里都有这个额外参数
1 | from django.urls import include, path |
后记
- 看doc基本看得一知半解,更清晰的理解需要认真阅读代码,我挺期待自己空下时间来阅读阅读大神的代码,但我太忙了
我太难了,我也不知道自己在忙啥,就是贼忙- 现在的中心大部分还在学校课时上,我尽力保障每周1-2更
- 《程序员的自我修养》看得比较慢,有点难…
Django入门——URL调度器