第三章 Django框架——路由控制解析
一、路由分配简介
二、简单的路由配置
三、无名分组与有名分组
四、路由分发
五、命名url与url反向解析
六、命名空间模式(名称空间)
七、Django1.x与Django2.x的路由区别
一、路由分配简介
什么是路由分配(what):
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。
你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
from django.urls import path urlpatterns = [ path('index', views.index), ]
二、简单的路由配置
Django1.1
from django.conf.urls import url from . import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# url(r'^index/$', views.index),
# url(r'^index/[0-9]{2,4}/', views.index),
url(r'^index/([0-9]{2,4})/([0-9]{4})/$', views.index),
]
正则表达式小复习:
$ 代表以...结尾(控制路由走向常用)
[0-9]{2,4} 代表以0到9之间的数字组成的2到4位数字
(正则表达式) 代表正则分组
+ 代表至少一个数字
Django2.0
from django.urls import path 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:slug>/', views.article_detail), ]
总结:
无论Django什么版本都是以下几个参数
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
1.正则表达式:一个正则表达式字符串
①urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
②不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
③每个正则表达式前面的'r' 是可选的但是建议加上。
2.views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
3.参数:可选的要传递给视图函数的默认参数(字典形式)
4.别名:一个可选的name参数
补充:
APPEND_SLASH
# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项 APPEND_SLASH=True
Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'。
我们定义了urls.py:
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^blog/$', views.blog), ]
访问 http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/ 。
如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求 http://www.example.com/blog 时就会提示找不到页面。
三、无名分组与有名分组
1.无名分组(分组匹配)
什么是无名分组(分组匹配)(what):
使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。
urls
urlpatterns = [ url(r'^admin/', admin.site.urls), # url(r'^index/$', views.index), # url(r'^index/[0-9]{2,4}/', views.index), url(r'^index/([0-9]{2,4})/([0-9]{4})/$', views.index), ]
views(a1,a2为位置传参)(即可以用*args接收值)
如上图,有两个分组,就要在对应函数里用两个值接收
def index(request,a1,a2): print(a1) # 符合([0,9]{2,4})的值 print(a2) # 符合([0,9){4})的值 return HttpResponse('ok')
举例:(通过出版社id删除出版社)
urls
views
删除链接修改为
2.有名分组(分组命名匹配)
什么是有名分组(分组命名匹配)(what):
在Python的正则表达式中,分组命名正则表达式组的语法是(?P<name>pattern)
,其中name
是组的名称,pattern
是要匹配的模式。
urls
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/(?P<year>[0-9]{2,4})/(?P<title>[a-zA-Z]{2})/$', views.index), ]
views(year,title为关键字传参)(即可以用**kwargs接收值)
def index(request,year,title): print("year",year) print("title",title) return HttpResponse('ok')
总结:
1.无名分组与有名分组不能混用
2.格式
无名分组:
url(r'^index/([0-9]{2,4})/([0-9]{4})/$', views.index)
有名分组:
url(r'^index/(?P<year>[0-9]{2,4})/(?P<title>[a-zA-Z]{2})/$', views.index)
3.views函数
无名分组:相当于给视图函数传递位置参数,可用*args接收值
有名分组:相当于给视图函数传递关键字参数,可用**kwargs接收值
4.切记:捕获到的参数是字符串str类型
每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:
url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
5.视图函数中可以指定默认值
# urls.py中 from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>[0-9]+)/$', views.page), ] # views.py中,可以为num指定默认值 def page(request, num="1"): pass
在上面的例子中,两个URL模式指向相同的view - views.page - 但是第一个模式并没有从URL中捕获任何东西。
如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值。
四、路由分发
通过Django内置的include方法进行路由分发。
路由分发步骤:
①在相应的app里创建urls.py文件
②导入url模块
③配置子路由
④切换到总路由urls,导入include
⑤配置总路由,通过^app01开头的一级路由分配到二级路由
⑥访问
注意:当导入两个相同名称的子路由时,一定要改名字!!!
注意:当导入两个相同名称的子路由时,一定要改名字!!!
注意:当导入两个相同名称的子路由时,一定要改名字!!!
五、命名url与url反向解析
在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:
- 在模板中:使用url 模板标签。
- 在Python 代码中:使用
from django.urls import reverse()函数
什么是url反向解析(what):
本质上就是给url匹配模式起别名,然后用过别名拿到具体的URL路径。
如何定义(how):
url(r'^home', views.home, name='home'), # 给我的url匹配模式起名为 home
如何调用(how):
模板语言
{% url "别名" 2018 "nb" %}
{% url 'home' 2018 ‘nb’%}
视图函数
- 传位置参数:
reverse("别名", args=(2018, "nb"))
- 传关键字参数:
reverse("别名" kwargs={"year": 2018, "title": "nb"})
return redirect(reverse('news-year-archive', args=(year,)))
注意:
如果反向解析的路由使用了无名分组或有名分组,就需要在reverse内传参
操作方法:
①定义路由时,使用name属性
②在html页面的链接内使用{%url ‘name’%}
也可以在{%url%}内传参
补充:
redirect中如何实现反向解析
①视图函数内导入reverse
②定义变量接收反向解析地址
注意:
如果反向解析的路由使用了无名分组或有名分组,就需要在reverse内传参。
③写进redirect
六、命名空间模式(名称空间)
命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
from django.conf.urls import url, include urlpatterns = [ url(r'^app01/', include('app01.urls', namespace='app01')), url(r'^app02/', include('app02.urls', namespace='app02')), ]
②子路由中设置反向解析
from django.conf.urls import url from app01 import views app_name = 'app01' urlpatterns = [ url(r'^(?P<pk>d+)/$', views.detail, name='detail') ]
③在另一个子路由中设置反向解析(与上一个反向解析name相同)
from django.conf.urls import url from app02 import views app_name = 'app02' urlpatterns = [ url(r'^(?P<pk>d+)/$', views.detail, name='detail') ]
④调用名称空间
模板中
{% url 'app01:detail' pk=12 pp=99 %}
视图函数中
v = reverse('app01:detail', kwargs={'pk':11})
七、Django1.x与Django2.x的路由区别
1.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), ]
2.存在path转化器
Django默认支持以下5个转化器:
- str,匹配除了路径分隔符(
/
)之外的非空字符串,这是默认的形式 - int,匹配正整数,包含0。
- slug,匹配字母、数字以及横杠、下划线组成的字符串。
- uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
- path,匹配任何非空字符串,包含了路径分隔符(/)(不能用?)
3.可以注册自定义的转化器
对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:
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), ... ]