Django 路由控制的实现


Posted in Python onJuly 17, 2019

一 Django中路由的作用

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

典型的例子:

from django.urls import path

urlpatterns = [
  path('articles', views.special),
]

articles这个路由对应着视图函数中special这个方法,浏览器输入这个链接,就会响应到special这个函数来执行

或者

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。

urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
]

参数说明:

    一个正则表达式字符串
    一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
    可选的要传递给视图函数的默认参数(字典形式)
    一个可选的name参数

二 简单的路由配置

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')。

在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你可以在你的视图函数定义中重新安排参数的顺序。当然,这些好处是以简洁为代价;

四 路由分发

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

urlpatterns = [

# re_path(r'^app01/',include('app01.urls')),#行

# re_path(r'^app01/&',include('app01.urls')),#不行

# path('app01/',include('app01.urls')),#行

# path('app01',include('app01.urls')),#不行
]

在app01里创建一个urls

from django.urls import path,re_path
from app01 import views
urlpatterns = [
  re_path(r'^test/(?P<year>[0-9]{2})/$',views.url_test),
]

五 反向解析

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

在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:

  • 在模板中:使用url 模板标签。
  • 在Python 代码中:使用from django.urls import reverse()函数

urls.py

from django.urls import path,re_path
from app01 import views
urlpatterns = [
  re_path(r'^test/(?P<year>[0-9]{2})/(?P<month>[0-9]{2})/$',views.url_test,name='test'),
]

html

<a href="{% url 'test' 10 23 %}" rel="external nofollow" >哈哈</a>

视图函数中:

from django.shortcuts import render, HttpResponse,redirect,reverse
def url_test(request,year,month):
  print(year)
  print(month)
  url=reverse('test',args=(10,20))
  print(url)
  return HttpResponse('ok')

总结:1 在html代码里{% url "别名" 参数  参数%}

 2 在视图函数中:

2.1 url=reverse('test')

2.2 url=reverse('test',args=(10,20))

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

六 名称空间

命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。

由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回

我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。

创建一个app02:python manage.py startapp app02

总urls.py

from django.urls import path,re_path,include
urlpatterns = [
  path('app01/', include('app01.urls')),
  path('app02/', include('app02.urls'))
]

app01 的urls.py

from django.urls import path,re_path
from app01 import views
urlpatterns = [
  re_path(r'index/',views.index,name='index'),
]

app02 的urls.py

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

urlpatterns = [
  re_path(r'index/', views.index,name='index'),

]

app01的视图函数

def index(request):
  url=reverse('index')
  print(url)
  return HttpResponse('index app01')

app02的视图函数

def index(request):
  url=reverse('index')
  print(url)
  return HttpResponse('index app02')

这样都找index,app01和app02找到的都是app02的index

如何处理?在路由分发的时候指定名称空间

总urls.py在路由分发时,指定名称空间

path('app01/', include(('app01.urls','app01'))),
 path('app02/', include(('app02.urls','app02')))
url(r'app01/',include('app01.urls',namespace='app01')),
 url(r'app02/',include('app02.urls',namespace='app02'))
url(r'app01/',include(('app01.urls','app01'))),
 url(r'app02/',include(('app02.urls','app02')))

在视图函数反向解析的时候,指定是那个名称空间下的

url=reverse('app02:index')
 print(url)
 url2=reverse('app01:index')
 print(url2)

在模版里:

<a href="{% url 'app02:index'%}" rel="external nofollow" >哈哈</a>

七 django2.0版的path

django2.0的re_path和1.0的url一样

思考情况如下:

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), 
]

 考虑下这样的两个问题:

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

第二个问题,三个路由中article_id都是同样的正则表达式,但是你需要写三遍,当之后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), 

# path才支持,re_path不支持

path('order/<int:year>',views.order),
]

基本规则:

  • 使用尖括号(<>)从url中捕获值。
  • 捕获值中可以包含一个转化器类型(converter type),比如使用 <int:name> 捕获一个整数变量。若果没有转化器,将匹配任何字符串,当然也包括了 / 字符。
  • 无需添加前导斜杠。

以下是根据 2.0官方文档 而整理的示例分析表:(跟上面url的匹配关系)

Django 路由控制的实现 

path转化器

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

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

  • str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
  • int,匹配正整数,包含0。
  • slug,匹配字母、数字以及横杠、下划线组成的字符串。
  • uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  • path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)

注册自定义转化器

对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:

  • regex 类属性,字符串类型
  • to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
  • 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对IP进行转换的一些操作技巧小结
Nov 09 Python
Python制作简单的网页爬虫
Nov 22 Python
Django自定义manage命令实例代码
Feb 11 Python
python数据分析数据标准化及离散化详解
Feb 26 Python
python批量从es取数据的方法(文档数超过10000)
Dec 27 Python
python 函数中的内置函数及用法详解
Jul 02 Python
python中的列表与元组的使用
Aug 08 Python
详解Python 字符串相似性的几种度量方法
Aug 29 Python
用python中的matplotlib绘制方程图像代码
Nov 21 Python
在keras 中获取张量 tensor 的维度大小实例
Jun 10 Python
Pycharm打开已有项目配置python环境的方法
Jul 03 Python
python实现自定义日志的具体方法
May 28 Python
详解python实现数据归一化处理的方式:(0,1)标准化
Jul 17 #Python
简单了解django索引的相关知识
Jul 17 #Python
python实现连连看辅助(图像识别)
Mar 25 #Python
Django中多种重定向方法使用详解
Jul 17 #Python
200行python代码实现2048游戏
Jul 17 #Python
Django后端接收嵌套Json数据及解析详解
Jul 17 #Python
Python制作微信好友背景墙教程(附完整代码)
Jul 17 #Python
You might like
PHP中计算字符串相似度的函数代码
2012/12/29 PHP
php中的常用魔术方法总结
2013/08/02 PHP
php安装xdebug/php安装pear/phpunit详解步骤(图)
2013/12/22 PHP
php使用filter过滤器验证邮箱 ipv6地址 url验证
2013/12/25 PHP
codeigniter教程之上传视频并使用ffmpeg转flv示例
2014/02/13 PHP
PHP图片处理之使用imagecopy函数添加图片水印实例
2014/11/19 PHP
Yii2超好用的日期和时间组件(值得收藏)
2016/05/05 PHP
laravel 数据迁移与 Eloquent ORM的实现方法
2019/04/12 PHP
laravel实现图片上传预览,及编辑时可更换图片,并实时变化的例子
2019/11/14 PHP
javascript 屏蔽鼠标键盘的几段代码
2008/01/02 Javascript
jquery text,radio,checkbox,select操作实现代码
2009/07/09 Javascript
Nodejs Post请求报socket hang up错误的解决办法
2014/09/25 NodeJs
javascript操作数组详解
2014/12/17 Javascript
在JavaScript中处理字符串之link()方法的使用
2015/06/08 Javascript
jQuery带时间的日期控件代码分享
2015/08/26 Javascript
JavaScript测试工具之Karma-Jasmine的安装和使用详解
2015/12/03 Javascript
JQuery实现网页右侧随动广告特效
2016/01/17 Javascript
浅谈js中调用函数时加不加括号的问题
2016/07/28 Javascript
基于JavaScript实现Tab选项卡切换效果
2016/11/24 Javascript
JS焦点图,JS 多个页面放多个焦点图的实例
2016/12/08 Javascript
javascript构造函数以及原型对象的理解
2017/01/13 Javascript
JS实现汉字与Unicode码相互转换的方法详解
2017/04/28 Javascript
vue项目实现设置根据路由高亮对应的菜单项操作
2020/08/06 Javascript
python操作excel文件并输出txt文件的实例
2018/07/10 Python
Python检查和同步本地时间(北京时间)的实现方法
2018/12/03 Python
Python实现微信消息防撤回功能的实例代码
2019/04/29 Python
Django接收post前端返回的json格式数据代码实现
2019/07/31 Python
Python内存泄漏和内存溢出的解决方案
2020/09/26 Python
欧舒丹澳洲版:L’OCCITANE
2017/07/17 全球购物
Final类有什么特点
2012/04/25 面试题
基于Python 函数和方法的区别说明
2021/03/24 Python
优秀老员工获奖感言
2014/02/15 职场文书
就业意向书
2014/07/29 职场文书
学校领导班子四风问题整改意见
2014/10/02 职场文书
入党团支部推荐意见
2015/06/02 职场文书
歌咏比赛口号大全
2015/12/25 职场文书