路由控制
一、Django中路由的作用
把视图函数与特定的 URL 对应起来,要使用 URL 配置(URLconf),URL 配置把 URL 映射到相应的视图函数上。我们以这种方式告诉 Django,“访问这个URL 时调用这些代码,访问那个 URL 时调用那些代码”。
二、
# 初始urls.py文件内容 from django.conf.urls import url from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), # Django后台管理URL ]
变量urlpatterns负责定义 URL 与处理URL 的代码之间的映射。
from django.conf.urls import url from django.contrib import admin from app import views #从应用中导入视图函数文件,此app泛指应用名 urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(正则表达式, views视图函数,参数,别名), ]
- 正则表达式:一个正则表达式字符串,匹配对应URL
- views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串(CBV则写法有所改变)
- 参数:可选的要传递给视图函数的默认参数(字典形式)
- 别名:一个可选的name参数
脱字符号^
表示“在字符串的开头匹配模式”,如果开头没有脱字符号(即 hello/$),Django 会匹配任何以 hello/ 结尾的 URL。
美元符号$
的意思是“在字符串的结尾匹配模式”,如果使用 ˆhello/ 模式(末尾没有美元符号),那么任何以 /hello/ 开头的 URL 字符串都能匹配,使用脱字符号和美元符号确保只匹配 /hello/ 这个 URL——不多不少。
urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。
如果请求的 URL 不匹配任何 URL 模式,而且末尾没有斜线,那么 Django 会把它重定向(redirect
)到末尾带斜线的 URL。这是Django默认的配置APPEND_SLASH=True所带来的的效果,一旦我们在settings.py配置文件中将其值改为FALSE,将不会自动在网址后面添加'/'。
三、无名分组
将加括号的正则表达式匹配到URL中的内容当做位置参数自动传递给相应的视图函数。
url(r'^test/(\d+)/',views.test), # \d+匹配一个或多个数字,使用圆括号从匹配的文本中捕获数据 def test(request,args): print(args) return HttpResponse('test')
四、有名分组
将加括号的命名的正则表达式匹配到URL中的内容当做关键字参数自动传递给相应的视图函数。
url(r'^test/(?P<example>\d+)/',views.test), def test(request,example): # 变量名必须和正则名字相同 print(example) return HttpResponse('test')
- 有名分组和无名分组无法混合使用
- 支持同一类型分组,多个匹配:r'^test/(?P<year>\d+)/(?P<mouth>\d+)/(?P<day>\d+)/'
五、反向解析
根据名字动态获取到对应路径,应用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
使用方法
from django.shortcuts import reverse # 为路由与视图函数对应关系起个名字,唯一标识对应路径,名字不可重复 url(r'^indexluan/$',views.index,name='index')
前端使用
{% url '你给路由与视图函数对应关系起的别名' %}
后端使用
reverse('你给路由与视图函数对应关系起的别名')
无名分组反向解析
url(r'^test/(\d+)/',views.test,name='example') # 后端使用 reverse('example',args=(加括号匹配到的内容,)) # 前端使用 {% url '你给路由与视图函数对应关系起的别名' 需传递的值 %}
有名分组反向解析
# 后端使用 # 后端有名分组和无名分组都可以用这种形式 reverse('example',args=(加括号匹配到的内容,)) # 下面这个了解即可 reverse('example',kwargs={加括号匹配到的内容('关键字参数':值)}) # 前端使用 # 前端有名分组和无名分组都可以用这种形式 {% url 'example' 需传递的值 %} # 下面这个了解即可 {% url 'example' 需传递的值(关键字参数=值) %}
六、路由分发
Django每一个app下面都可以有自己的urls.py路由层,templates文件夹,static文件夹。项目名下的urls.py(总路由)不再做路由和视图函数的匹配关系,而是做路由的分发。
1.起别名的方式避免冲突
# 总路由下 from django.conf.urls import include from app01 import urls as app01_urls from app02 import urls as app02_urls # 路由分发 注意路由分发总路由千万不要$结尾 url(r'^app01/',include(app01_urls)), url(r'^app02/',include(app02_urls)) # 在应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系即可 from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/',views.index) ]
2.写成字符串形式(importlib)
# 总路由下 from django.conf.urls import include # 路由分发 注意路由分发总路由千万不要$结尾 url(r'^app01/',include('app01.urls')), url(r'^app02/',include('app02.urls')) # 在应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系即可 from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/',views.index) ]
七、名称空间
命名空间(英语:Namespace)是表示标识符的可见范围。一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的。这样,在一个新的命名空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其它命名空间中。
由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回。
错误场景
# 总路由下 from django.conf.urls import include # 路由分发 注意路由分发总路由千万不要$结尾 url(r'^app01/',include('app01.urls')), url(r'^app02/',include('app02.urls')) # 在应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系,为其取名index from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/',views.index,name='index') ] # 在应用下新建urls.py文件,在该文件内写路由与视图函数的对应关系,也为其取名index from django.conf.urls import url from app02 import views urlpatterns = [ url(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
解决方案
此时我们需要在路由分发的时候指定名称空间
# 总路由下 from django.conf.urls import include # 路由分发 注意路由分发总路由千万不要$结尾 url(r'app01/',include('app01.urls',namespace='app01')), url(r'app02/',include('app02.urls',namespace='app02'))
视图函数下反向解析
# app01.views.py url = reverse('app01:index') # app02.views.py url = reverse('app02:index')
模板里反向解析
<a href="{% url 'app01:index'%}">解决</a>
注:一般来说,我们会在反向解析命名的时候加以区分,例如app01下的index,我们就以name = app01_index处理。