路由控制
内容概要
- 路由匹配
- 无名分组有名分组
- 反向解析
- 无名有名反向解析
- 路由分发
- include
- 名称空间
内容详细
路由匹配
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。
- Django 1.11 版本的 URLconf 配置:
from django.conf.urls import url
urlpatterns = [
url(正则表达式, views视图函数,参数,别名),
]
正则表达式: 一个正则表达式字符串
views视图函数: 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
参数: 可选的要传递给视图函数的默认参数(字典形式)
别名: 一个可选的name参数,做反向解析时使用
from django.conf.urls import url
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^library/', views.library, {'username': 'elijah'}),
url(r'^login/', views.login,name='login')
]
- Django 2.0 和 3.0 版本路由配置变成了下面写法:
from django.urls import path, re_path
urlpatterns = [
path('admin/', admin.site.urls),
path('login/<int:name>', views.login),
re_path('^$', views.index, name='index'),
]
# re_path 和 1 版本的 url 用法一样,支持正则匹配
正则匹配
在 Django 1.0 版本的 url 支持正则匹配路由,在 2.0 以上版本也有 re_path 支持路由正则匹配
from django.conf.urls import url
from app01 import views
urlpatterns = [
url(r'^$', views.index),
url(r'^login/[0-9A-Z]{1,3}/', views.login),
url(r'^register/', views.reg),
url(r'', views.tail),
]
# r'' 可以取消字符串中特殊字符转义
# ^ 上尖号表示以后面的字符开头
# $ 美元符号表示以前面字符结尾
# r'^$' 表示启动django进入初始页调用后面的视图函数
# r'' 表示路由匹配不成功调用后面的视图函数,但该路由要放在最末尾的位置
补充:
路由匹配是按照配置中从上往下匹配,为了避免以下所示,匹配错误的路由地址,才在每个路由后面加上 ' / ' 符号,在获取用户输入的路由地址后会在列表中从上往下匹配一遍,如果找不到目标,会自动在后面加上 ' / ' 符号再匹配一次
urlpatterns = [
url(r'^test', views.test),
url(r'^testadd', views.testadd),
]
如果想要取消自动加上 ' / ' 符号的功能,可以在配置文件 settings.py 中添加常量:
但不建议这样子做
# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项
APPEND_SLASH=True
# 关闭效果
APPEND_SLASH=False
无名分组有名分组
分组: 就是用括号括起来某一段正则表达式,正则匹配的结果会与请求数据 request 一起当作参数传给对应的视图函数
urlpatterns = [
url(r'^test/([a-z]{3,})/', views.test),
]
无名分组: 就是括号内的正则匹配结果会当作位置实参传给视图函数,视图函数除了 request 参数还要另多写一个形参来接收分组的匹配结果
urlpatterns = [
url(r'^test/(\d+)/', views.test),
]
def test(request, num):
return HttpResponse('ok')
有名分组: 就是给括号内的分组起个别名,然后正则匹配结果当作关键字参数 '' name = 'elijah' '' 的形式传给视图函数,视图函数需要用关键字形参来接收。
urlpatterns = [
url(r'^testadd/(?P<number>\d+)/', views.testadd),
]
def test(request, number):
return HttpResponse('ok')
注意: 有名分组与无名分组不能混用,但同一个分组可以使用多次
urlpatterns = [
url(r'^test/(\d+)/(\d+)/(\d+)/', views.test),
]
反向解析
简单来说就是可以给我们的URL匹配规则起个名字,一个URL匹配模式起一个名字。
给路由匹配起一个别名:name='home'
这样,无论是在前端或者后端,都可以通过 'home' 这个别名找到它的路由地址,并触发相应的视图函数
记住: 通过一些方法可以得到一个结果,该结果可以直接访问对应的 url 并触发相应的视图函数
例子:
urlpatterns = [
url(r'^test/', views.test, name='test'),
]
前端跳转:
<p>反向解析: <a href="{% url 'test' %}">test界面</a></p>
后端:
from django.urls import reverse
def reg(request):
print(reverse('test'))
return render(request, 'register.html')
# 打印结果
/test/
前端效果:
无名有名反向解析
在进行反向解析的同时,也可以给 url 传参,无名就是以位置参数的形式传入参数,有名就是以关键字参数的形式传入参数,但两者都可以使用相同且简便的方式传入参数,就不分开描述了
路由:
urlpatterns = [
url(r'^test/(\d+)', views.test, name='test'),
]
前端传参:
<p>反向解析: <a href="{% url 'test' 123 %}">test界面</a></p>
后端:
print(reverse('test', arg=(123, )))
意义: 无名有名反向解析带来了 除 GET请求方式 (?name='elijah') 之外的又一种给后端传参的方式
路由分发
当一个 Django 项目中有多个应用功能,需要进行分组开发再整合,每个程序员开发开发一个功能,大家协同开发,那么每个人都可以在自己的应用文件中创建自己的 urls.py 文件,用于存放各自应用的路由与视图函数对应关系,
那么,在总目录下的 urls.py 文件中就得做好各应用的路由分发
请求来的时候根据用户输入的不同应用地址把请求分发到相应的应用下的 urls.py 文件中去
主目录下的 urls.py 文件:
"""djangoProject URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/2.2/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
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 = [
path('login/<int:name>', views.login),
re_path('^$', views.index, name='index'),
path('login/', views.login, name='login'),
path('home/', views.MyClass.as_view(), name='home'),
path('index/', views.index, name='index'),
path('beauty/', views.beauty, name='beauty'),
path('test/', views.test, name='test'),
path('test1/', views.test1, name='test1')
]
app02 文件 urls.py:
from django.urls import path, re_path
from app02 import views
urlpatterns = [
path('test/', views.test),
]
名称空间
多个应用同时开发时,有可能会出现路由别名一样的情况
这时后端的反向解析没办法识别路由地址是属于哪个应用的,这时,就需要在主目录下的路由分发后声明相应的名称空间,这样后端可以通过添加应用前缀来分辨路由
project中的urls.py
from django.conf.urls import url, include
urlpatterns = [
url(r'^app01/', include('app01.urls', namespace='app01')),
url(r'^app02/', include('app02.urls', namespace='app02')),
]
app01中的urls.py
from django.conf.urls import url
from app01 import views
app_name = 'app01'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]
app02中的urls.py
from django.conf.urls import url
from app02 import views
app_name = 'app02'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='detail')
]
现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。
注意: 在实际开发中,其实我们在给每个路由起别名的时候可以添加应用名称的前缀,这样便可以避免重名了
from django.conf.urls import url
from app01 import views
app_name = 'app01'
urlpatterns = [
url(r'^(?P<pk>\d+)/$', views.detail, name='app01_detail')
]