Django路由层
Django
路由层的功能就是匹配用户的资源请求,通过资源匹配路径来运行相应的视图层功能。
路径匹配
匹配顺序
Django
中的资源请求路径匹配是按照从上至下的顺序进行。
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls), # ↓
url(r'^f1/', views.f1), # ↓
url(r'^f2/', views.f2), # ↓
url(r'^f3/', views.f3), # ↓
]
正则匹配
匹配方式为正则匹配,因此要注意使用^
与$
的使用。
由于匹配行为是从上至下,所以在定义时一定要注意顺序。
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^f', views.f1),
url(r'^f', views.f2),
url(r'^f', views.f3),
]
# 无论输入f几,都是进入的f1的处理函数。
介绍两个关于主页和尾页的匹配规则
主页:
'^$'
此时直接访问地址即可访问成功尾页:
''
注意放在最后,这代表没匹配成功时将会弹出的信息,可以定义一个404
的页面进行返回。
重新匹配
如果第一次匹配没匹配上,那么在第二次匹配时Django
会要求浏览器对路径进行加/
的处理重新再匹配一次,所以你将看到以下现象。
有两次请求:
关闭Django
要求浏览器加/
的重新匹配行为,可在设置文件中加上如下代码:
APPEND_SLASH = False # 默认为True
匹配分组
匹配分组常用于提取出请求资源地址上一些能够被利用的信息,如id
,日期等。
分组中的数据将以参数形式传递给视图函数。
无名分组
单纯的分组,不取名字即为无名分组。
注意:无名分组匹配到的组内容会当作位置参数传递给后面的视图函数。
视图层匹配规则
url(r'^date/(\d+)-(\d+)-(\d+)/$', views.date),
视图层中的处理函数
def date(request,v1,v2,v3): # 位置与分组一一对应即可
return HttpResponse("{0}-{1}-{2}".format(v1,v2,v3))
请求的URL
http://127.0.0.1:8000/date/2020-01-28/
最终结果
2020-01-28
有名分组
有名分组即为分组取一个名字。
注意:有名分组匹配到的组内容会当作关键字参数传递给后面的视图函数,这代表视图函数中的参数与分组名字必须一致。
视图层匹配规则
url(r'^date/(?P\d+)-(?P\d+)-(?P\d+)/$', views.date),
视图层中的处理函数
def date(request,year,month,day): # 必须与分组名相同
return HttpResponse("{0}-{1}-{2}".format(year,month,day))
请求的URL
http://127.0.0.1:8000/date/2020-01-28/
最终结果
2020-01-28
混合使用
需要注意的是Django
中不支持无名与有名分组的混合使用。
如果混合使用,无名分组将拿不到数据。
http://127.0.0.1:8000/date/2020-01-28/
url(r'^date/(\d+)-(?P\d+)-(?P\d+)/$', views.date),
def date(request,*args,**kwargs):
return HttpResponse("{0}-{1}".format(args,kwargs))
# ()-{'month': '01', 'day': '28'}
反向解析
为URL
匹配规则起一个别名,通过该别名可以转换为请求资源路径。
匹配别名
可以为匹配规则取一个别名,但是一定要注意!别名不能出现冲突。
url(r'^login/',views.login,name="login"),
前端解析
如果前端中都写固定的请求资源路径,那么该路径的匹配规则一改就都匹配不到了。
所以更推荐取别名来使用反向解析来进行操作。即点击标签跳转到
test
视图函数处理中。
无参数前端反向解析:
前端反向解析
url(r'^test/',views.login,name="test"),
def test(request):
,,,
无名分组前端反向解析:
前端反向解析(无名分组) # 参数必须一一对应
url(r'^test/-(\d+)-(\d+)-(\d+)',views.login,name="test"),
def test(request,v1,v2,v3): # 参数必须一一对应
...
有名分组前端反向解析:
前端反向解析(有名分组) # 参数必须一一对应
url(r'^test/-(?P\d+)-(?P\d+)-(?P\d+)',views.login,name="test"),
def test(request,year,month,day): # 参数必须一一对应
...
后端解析
后端的反向解析常用在跳转中,如登陆完成后跳转到首页就可以使用后端反向解析。
后端使用反向解析,要先进行模块功能的导入。
这是最常用的,后端无参反向解析。
from django.shortcuts import reverse
def login(request):
return redirect(reverse('index')) # 登录完成后跳转到index页面
url(r'^index/',views.index,name="index"), # 匹配规则,跳转到index
def index(request):
...
如果后端反向解析的匹配规则中带有无名分组,则需要使用args
关键字参数将参数带上。
from django.shortcuts import reverse
def login(request):
return redirect(reverse('index',args=(111,222,333)))
url(r'^index/-(\d+)-(\d+)-(\d+)',views.index,name="index"), # 匹配规则,跳转到index
def index(request,v1,v2,v3):
...
如果后端反向解析的匹配规则中带有有名分组,则需要使用kwargs
关键字参数将参数带上。
def login(request):
return redirect(reverse('index', kwargs={"year": 2020, "month": 12, "day": 28}))
url(r'^index/--(?P\d+)-(?P\d+)-(?P\d+)',views.index,name="index"), # 匹配规则,跳转到index
def index(request, year, month, day):
...
路由分发
Django
允许在每个APP
下拥有templates
文件夹,static
文件夹,当然也可以拥有urls.py
文件夹。
路由分发的作用在于缓解项目全局文件夹下urls.py
的代码冗余度,此外还可以进行非常给力的分组开发。
基本使用
首先我们要在app01
与app02
下创建两个urls.py
。
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'f1/',views.f1,name="app01_f1")
]
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="app02_f1")
]
然后要在项目全局文件夹下的urls.py
中导入路由分发模块,然后导入app01
以及app02
下的urls.py
。
from django.conf.urls import url
from django.conf.urls import include # 导入路由分发模块
from app01 import urls as app01_urls
from app02 import urls as app02_urls
urlpatterns = [
url(r'app01/',include(app01_urls)),
url(r'app02/',include(app02_urls)),
]
这样在url
中输入不同的前缀就能访问不同的APP
下对应的视图功能。
http://127.0.0.1:8000/app01/f1/ # app01的urls处理该请求
http://127.0.0.1:8000/app02/f1/ # app02的urls处理该请求
快捷使用
基本的路由分发使用还需要在项目全局文件夹下的urls.py
中导入不同APP
中的urls.py
,这样有点繁琐。
其实可以直接如下代码这样做更加简便,都不用导入不同APP
下的urls.py
了。
from django.conf.urls import url
from django.conf.urls import include # 导入路由分发模块
urlpatterns = [
url(r'app01/', include('app01.urls')),
url(r'app02/', include('app02.urls')),
]
命名空间
如果不同的APP
中,匹配别名相同则会造成命名空间冲突的问题。
此时我们需要在项目总文件夹的urls.py
中对路由分发的路径使用命名空间,然后才可以使用反向解析。
reverse("f1") # 命名空间冲突,始终解析的是app02下的f1
{% url 'f1' %}
# ======================================
from django.conf.urls import url
from django.conf.urls import include # 导入路由分发模块
urlpatterns = [
url(r'app01/', include('app01.urls')),
url(r'app02/', include('app02.urls')), # 注意,app02在下面
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f1") # app01里的f1
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f2") # app02里的f1
]
reverse("app01:f1") # 反向解析时使用先拿到命名空间,再那里面的路径别名
{% url 'app01:f1' %}
# ======================================
from django.conf.urls import url
from django.conf.urls import include # 导入路由分发模块
urlpatterns = [
url(r'app01/', include('app01.urls',namespace="app01")), # 命名空间 app01
url(r'app02/', include('app02.urls',namespace="app02")), # 命名空间 app02
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f1") # app01里的f1
]
# ======================================
from django.conf.urls import url
from app02 import views
urlpatterns = [
url(r'f1/',views.f1,name="f2") # app02里的f1
]