Django之路由层的实现


Posted in Python onSeptember 09, 2019

URL配置(URLconf)就像Django所支撑网站的目录。它的本指是URL与要为该URL调用的视图函数之间的映射表,你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。

一、简单的路由配置

from django.urls import path,re_path

from app01 import views

urlpatterns = [
re_path(r'^articles/2003/$', views.special_case_2003),
re_path(r'^articles/([0-9]{4})/$', views.year_archive),
re_path(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
re_path(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

注:若要从URL中捕获一个值,只需要在它周围放置一对圆括号。不需要添加一个前导的反斜杠,因为每个URL都有。例如,应该是 ^articles 而不是 ^/articles 。每个正则表达式前面的 r 是可选的,但是建议加上,它告诉Python这个字符串是“原始的”——字符串中任何字符都不应该转义。

一些请求的例子:

/articles/2005/03/ 请求将匹配列表中的第三个模式。Django 将调用函数views.month_archive(request, '2005', '03')。
/articles/2005/3/ 不匹配任何URL 模式,因为列表中的第三个模式要求月份应该是两个数字。
/articles/2003/ 将匹配列表中的第一个模式不是第二个,因为模式按顺序匹配,第一个会首先测试是否匹配。请像这样自由插入一些特殊的情况来探测匹配的次序。
/articles/2003 不匹配任何一个模式,因为每个模式要求URL 以一个反斜线结尾。
/articles/2003/03/03/ 将匹配最后一个模式。Django 将调用函数views.article_detail(request, '2003', '03', '03')。

二、有名分组

上面的示例使用简单的、没有命名的正则表达式(通过圆括号)来捕获URL中的额值并以位置参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL中的值并以关键字参数传递给视图。在Python正则表达式中,命名正则表达式组的语法是 (?P<name>pattern) ,其中name是组的名称,pattern是要匹配的模式。下面是以上URLconf使用命名组的重写:

from django.urls import path,re_path

from app01 import views

urlpatterns = [
re_path(r'^articles/2003/$', views.special_case_2003),
re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]

这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。例如:

/articles/2005/03/ 请求将调用views.month_archive(request, year='2005', month='03')函数,而不是views.month_archive(request, '2005', '03')。
/articles/2003/03/03/ 请求将调用函数views.article_detail(request, year='2003', month='03', day='03')。

三、分发

'''
At any point, your urlpatterns can “include” other URLconf modules. This
essentially “roots” a set of URLs below other ones.
'''

from django.urls import path,re_path,include
from app01 import views

urlpatterns = [
re_path(r'^admin/', admin.site.urls),
re_path(r'^blog/', include('blog.urls')),
]

四、反向解析

在使用Django项目时,一个常见的需求是获得URL的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf毫不相关的专门的URL生成机制,因为这样容易导致一定程度上产生过期的URL。在需要URL的地方,对于不同层级,Django提供不同的额工具用于URL反查:

1、在模板中:使用URL模板标签。

2、在Python代码中:使用 from django.urls import reverse 函数 urls.py:

from django.conf.urls import url

from . import views

urlpatterns = [
#...
re_path(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
#...
]

在模板中:

<a href="{% url 'news-year-archive' 2012 %}" rel="external nofollow" >2012 Archive</a>

<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}" rel="external nofollow" >{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

在python中:

from django.urls import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
# ...
year = 2006
# ...
return HttpResponseRedirect(reverse('news-year-archive', args=(year,))) # 同redirect("/path/")

当命名你的URL模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。在URL名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是 comment。

五、名称空间

命名空间(Namespace)是标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回。我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。

在项目的urls.py中:

urlpatterns = [
re_path(r'^admin/', admin.site.urls),
re_path(r'^app01/', include(("app01.urls",namespace="app01"))),
re_path(r'^app02/', include(("app02.urls",namespace="app02"))),
]

app01.urls:

urlpatterns = [
re_path(r'^index/', index,name="index"),
]

app02.urls:

urlpatterns = [
re_path(r'^index/', index,name="index"),
]

app01.views:

from django.core.urlresolvers import reverse
def index(request):
  return HttpResponse(reverse("app01:index"))

app02.views:

from django.core.urlresolvers import reverse
def index(request):
  return HttpResponse(reverse("app02:index"))

六、Django2.0版本的path

urlpatterns = [
re_path('articles/(?P<year>[0-9]{4})/', year_archive),
re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),
re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),
re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),
]

考虑一下这样的两个问题:

1、函数year_archive中year参数是字符串类型,因此需要先转换为整数类型的变量值,当然year = int(year)不会有诸如TypeError或者VaError的异常。那么有没有一种方法,在url中,使得这一转换步骤可以由Django自动完成?

2、三个路由中article_id规则改变后,需要同时修改三处代码,那么有没有一种方法,只需要修改一处即可?

在Django2.0版本中,可以使用path解决以上的两个问题。

简单示例:

from django.urls import path 
from . import views 
urlpatterns = [ 
  path('articles/2003/', views.special_case_2003), 
  path('articles/<int:year>/', views.year_archive), 
  path('articles/<int:year>/<int:month>/', views.month_archive), 
  path('articles/<int:year>/<int:month>/<slug>/', views.article_detail), 
]

基本规则:

1、使用尖括号 <> 从url中捕获值。

2、捕获值中可以包含一个转换器类型(converter type),比如使用<int : name>捕获一个整数变量。如果没有转换器,将匹配任何字符串,当然也包括了 / 字符。

3、无需添加前导斜杠。

以下是根据https://docs.djangoproject.com/en/2.0/topics/http/urls/#example而整理的示例分析表:

Django之路由层的实现

path转换器:

文档原文是Path converters,暂且翻译为转换器。

Django默认支持以下5个转换器:

1、str——匹配除了路径分隔符 / 之外的非空字符串,这是默认的形式。

2、int——匹配正整数,包含0。

3、slug——匹配字母、数字以及横杠、下划线组成的字符串。

4、uuid——匹配格式化的uuid,如075194d3-6885-417e-a8a8-6c931e272f00。

5、path——匹配任何非空字符串,包含了路径分隔符。

注册自定义转换器:

对于一些复杂或者复用的需要,可以定义自己的转换器。

转换器是一个类或者接口,它的要求有三点:

1、regex类属性,字符串类型。

2、to_python(self, value)方法,value是由类属性regex所匹配到的字符串没返回具体的Python变量值,以供Django传递到对应的视图函数中。

3、to_url(self, value)方法,和to_python相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。

示例:

class FourDigitYearConverter: 
  regex = '[0-9]{4}' 
  def to_python(self, value): 
    return int(value) 
  def to_url(self, value): 
    return '%04d' % value

使用register_converter将其注册到URL配置中:

from django.urls import register_converter, path 
from . import converters, views 
register_converter(converters.FourDigitYearConverter, 'yyyy') 
urlpatterns = [ 
  path('articles/2003/', views.special_case_2003), 
  path('articles/<yyyy:year>/', views.year_archive), 
  ... 
]

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python基于右递归解决八皇后问题的方法
May 25 Python
在Python的while循环中使用else以及循环嵌套的用法
Oct 14 Python
python从入门到精通(DAY 1)
Dec 20 Python
Python基于回溯法子集树模板解决取物搭配问题实例
Sep 02 Python
使用Python &amp; Flask 实现RESTful Web API的实例
Sep 19 Python
基于windows下pip安装python模块时报错总结
Jun 12 Python
获取python的list中含有重复值的index方法
Jun 27 Python
python进行两个表格对比的方法
Jun 27 Python
python3 实现对图片进行局部切割的方法
Dec 05 Python
Python数据结构dict常用操作代码实例
Mar 12 Python
关于keras中keras.layers.merge的用法说明
May 23 Python
Python 获取异常(Exception)信息的几种方法
Dec 29 Python
python中web框架的自定义创建
Sep 08 #Python
python web框架中实现原生分页
Sep 08 #Python
python中open函数的基本用法示例
Sep 07 #Python
Python3显示当前时间、计算时间差及时间加减法示例代码
Sep 07 #Python
利用python计算时间差(返回天数)
Sep 07 #Python
Django配置MySQL数据库的完整步骤
Sep 07 #Python
Django项目创建到启动详解(最全最详细)
Sep 07 #Python
You might like
使用php将某个目录下面的所有文件罗列出来的方法详解
2013/06/21 PHP
php三维数组去重(示例代码)
2013/11/26 PHP
php查找任何页面上的所有链接的方法
2013/12/03 PHP
php不使用插件导出excel的简单方法
2014/03/04 PHP
PHP实现的一致性Hash算法详解【分布式算法】
2018/03/31 PHP
JavaScript 空位补零实现代码
2010/02/26 Javascript
javascript抖动元素的小例子
2013/10/28 Javascript
js动态设置div的值下例子
2013/10/29 Javascript
js与C#进行时间戳转换
2014/11/14 Javascript
Bootstrap打造一个左侧折叠菜单的系统模板(一)
2016/05/17 Javascript
jQuery向父辈遍历的简单方法
2016/09/18 Javascript
JS点击某个图标或按钮弹出文件选择框的实现代码
2016/09/27 Javascript
使用vue实现grid-layout功能实例代码
2018/01/05 Javascript
mpvue性能优化实战技巧(小结)
2019/04/17 Javascript
vue调用微信JSDK 扫一扫,相册等需要注意的事项
2021/01/03 Vue.js
Python统计列表中的重复项出现的次数的方法
2014/08/18 Python
Python采用Django制作简易的知乎日报API
2016/08/03 Python
Python IDLE入门简介
2017/12/08 Python
PyQt5每天必学之布局管理
2018/04/19 Python
python实现二级登陆菜单及安装过程
2019/06/21 Python
tensorflow实现在函数中用tf.Print输出中间值
2020/01/21 Python
tensorflow之tf.record实现存浮点数数组
2020/02/17 Python
Python如何使用bokeh包和geojson数据绘制地图
2020/03/21 Python
Python爬虫代理池搭建的方法步骤
2020/09/28 Python
通过代码简单了解django model序列化作用
2020/11/12 Python
Html5游戏开发之乒乓Ping Pong游戏示例(三)
2013/01/21 HTML / CSS
美国领先的精品家居照明和装饰产品在线零售商:LightsOnline.com
2018/01/23 全球购物
巴西备受欢迎的服装和生活方式品牌:FARM Rio
2020/02/04 全球购物
冰淇淋店创业计划书范文
2013/12/27 职场文书
内勤主管岗位职责
2014/04/03 职场文书
关爱留守儿童标语
2014/06/18 职场文书
总经理岗位职责说明书
2014/07/30 职场文书
授权委托书格式
2014/07/31 职场文书
招标授权委托书样本
2014/09/23 职场文书
村主任群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
学习社交礼仪心得体会
2016/01/22 职场文书