Django路由
1.简单的路由配置
from django.contrib importadminfrom django.urls importpath, re_path#django 2.往后的版本,要使用正则,需要引入re_path
#必须导入自己创建的应用里的views视图.py文件
from app01 importviews
urlpatterns=[#根据客户端请求的路径,分配路由。
#path()是完全匹配,re_path()是使用正则匹配
#path("login/")相当于re_path(r"^login/$") 路径指定以l开头,以/结尾
re_path(r'^articles/2003/$', views.special_case_2003),
path("articles/2003/",views.special_case_2003),
]
注意:
若要从URL 中捕获一个值,使用re_path(),需要在正则里的周围放置一对圆括号(分组)。
不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义
正则里最好使用 ^ 和 $ 来约束开头和结尾
2. re_path( )里的正则,使用无名分组,获取url中需要的参数
使用re_path() 正则里的分组,来获取GET请求中,url路径中需要的部分参数,便于在视图(views.py的函数)里使用。
注意: 无名分组,一个正则中匹配的多个分组项,是按位置和视图函数一一对应的
urls.py内容如下:
from django.contrib importadminfrom django.urls importpath, re_path#django 2.往后的版本,要使用正则,需要引入re_path
#必须导入自己创建的应用里的views视图.py文件
from app01 importviews
urlpatterns=[#根据客户端请求的路径,分配路由。
#path()是完全匹配,re_path()是使用正则匹配
#path("login/")相当于re_path(r"^login/$") 路径指定以l开头,以/结尾
#【重要】 re_path里的正则表达式里,如有()进行了分组,则匹配成功后,会将匹配的分组内容,当作参数,调用views.py里对应的函数
re_path(r"^articles/2003/$", views.special_year), #special_year(request)
re_path(r"^articles/(\d{4})/$", views.year_archive), #year_archive(request,'2020')
re_path(r"^articles/(\d{4})/(\d{2})/$", views.year_month_archive), #year_archive(request,'2020','01')
#【注意】路由很多时,一定要注意上下匹配先后问题,程序从上往下执行,一旦匹配成功,马上执行,后面的即使能匹配,也不执行了。
#浏览器输入: https://127.0.0.1:8000/articles/2003/ 调用views.py里的 special_year(request),而不是调用 year_archive(request,'2003'),因为只执行一次匹配
#浏览器输入: https://127.0.0.1:8000/articles/2020 调用views.py里的 year_archive(request,'2020')
#浏览器输入: https://127.0.0.1:8000/articles/2020/01 调用views.py里的 year_month_archive(request,'2020','01')
]
views.py内容如下:
from django.shortcuts importrender,HttpResponse#render是一个函数,HttpResponse是一个类
#Create your views here.
importtime,datetimedefspecial_year(request):#去数据库查询所有2003年的文章
return HttpResponse("special_year:2003 OK")defyear_archive(request,year): #这里的year拿到的是 字符串类型#去数据库查询所有指定年份的文章
returnHttpResponse(year)defyear_month_archive(request,year,month):#去数据库查询指定年、指定月份的文章
return HttpResponse("year:%s month:%s" %(year,month))
使用浏览器访问:
-----
----
3.有名分组 (对比上面的无名分组)
正则里使用 ( )进行分组
使用 ?P< 关键字> 来给该分组起名字
urls.py如下:
from django.contrib importadminfrom django.urls importpath, re_path#django 2.往后的版本,要使用正则,需要引入re_path
#必须导入自己创建的应用里的views视图.py文件
from app01 importviews
urlpatterns=[#根据客户端请求的路径,分配路由。
#path()是完全匹配,re_path()是使用正则匹配
#path("login/")相当于re_path(r"^login/$") 路径指定以l开头,以/结尾
#无名分组
#re_path(r"^articles/(\d{4})/(\d{2})/$", views.year_month_archive), # year_archive(request,2020,01)
#有名分组 ()用来分组; ?P用来给该分组起个名字(关键字)
re_path(r"^articles/(?P\d{4})/(?P\d{2})/$", views.year_month_archive2), #year_archive2(request,year='2020',month='01')]
views.py如下:
from django.shortcuts importrender,HttpResponse#render是一个函数,HttpResponse是一个类
defspecial_year(request):#去数据库查询所有2003年的文章
return HttpResponse("special_year:2003 OK")defyear_archive(request,year):#去数据库查询所有指定年份的文章
returnHttpResponse(year)def year_month_archive(request,year,month): #无名分组时,year 和 month 的前后位置关系,必须和路由里的正则匹配时一样。 另外,无名分组的函数里,参数名可以随便起,例如 year_month_archive(request,y,m)也是可以的。
#去数据库查询指定年、指定月份的文章
return HttpResponse("year:%s month:%s" %(year,month))def year_month_archive2(request,month,year): #有名分组时,year和month参数,顺序就可以打乱写了。 有名分组里的函数的参数名,必须和正则里的分组名一样,否则函数调用时会报错。
#去数据库查询指定年、指定月份的文章
return HttpResponse("year:%s month:%s" %(year,month))
4.路由分发 (适合较大项目,项目下有多个应用)
当项目较大时,再使用全局的urls.py来分发到多个不同应用的视图函数,会降低阅读、维护的难度。
所以,可以通过全局urls.py首先根据应用,进行首次路由分发到各个应用的urls.py。到达应用层后,再由各个应用的urls.py进行分发到视图函数。
4.1 全局 url.py
#全局 urls.py
from django.urls importpath, re_path, include#django 2.往后的版本,要使用正则,需要引入re_path
#如果项目较大,有多个应用,则在全局的路由里,需要进行一次路由分发,即发送到各个应用的路由。需要引入include()函数
urlpatterns=[#根据客户端请求的路径,首先分配到各个应用的路由。
#此示例中,整个项目首页,也分发在一个应用里,该应用只用来显示主页
re_path("^$",include("app_index.urls")), #以空开头,以空结尾,匹配根目录。一般用来显示主页等。
#根据项目里的应用,进行路由分发
re_path('app01/', include('app01.urls')), #从url从匹配到 "app01"后,将后面的路径,分发到 app01.url.py的路由里
re_path('app02/', include('app02.urls')), #从url从匹配到 "app02"后,将后面的路径,分发到 app02.url.py的路由里
]
全局 urls.py
4.2 各应用的 urls.py (需要自己创建该.py文件。可以直接复制全局的代码过来,稍作修改)
app01的urls.py:
app02的urls.py:
app_index的 urls.py:
#app01的urls.py
from django.contrib importadminfrom django.urls importpath, re_path#django 2.往后的版本,要使用正则,需要引入re_path
#必须导入自己创建的应用里的views视图.py文件
from app01 importviews
urlpatterns=[
re_path("^$", views.index), #分发到 应用app01的首页
re_path(r"^articles/2003/$", views.special_year), #special_year(request)
re_path(r"^articles/(\d{4})/$", views.year_archive), #year_archive(request,'2020')
#有名分组 ()用来分组; ?P用来给该分组起个名字(关键字)
re_path(r"^articles/(?P\d{4})/(?P\d{2})/$", views.year_month_archive2), #year_archive2(request,year='2020',month='01')
]
# app01的urls.py
#app02的 urls.py
from django.contrib importadminfrom django.urls importpath, re_path#django 2.往后的版本,要使用正则,需要引入re_path
#必须导入自己创建的应用里的views视图.py文件
from app02 importviews
urlpatterns=[
re_path("^$",views.index), #分发到 应用app02的首页
re_path("^timer/$",views.timer),
]
# app02的urls.py
#app_index 的 urls.py
from django.contrib importadminfrom django.urls importpath, re_path#django 2.往后的版本,要使用正则,需要引入re_path
#必须导入自己创建的应用里的views视图.py文件
from app_index importviews
urlpatterns=[
re_path("^$", views.index), #发到 应用app_index的首页,此示例,把此应用的首页,作为整个项目的首页
]
# app_index的 urls.py
4.3 各应用的 views.py
4.4 使用浏览器访问:
==
==
==
#app_index的views.py
from django.shortcuts importrender,HttpResponse#render是一个函数,HttpResponse是一个类
#Create your views here.
#函数1 主页
defindex(request):return HttpResponse("项目 主页")
# app_index的views.py
#app01 的views.py
from django.shortcuts importrender,HttpResponse#render是一个函数,HttpResponse是一个类
#Create your views here.
importtime,datetimedefspecial_year(request):#去数据库查询所有2003年的文章
return HttpResponse("special_year:2003 OK")defyear_archive(request,year):#去数据库查询所有指定年份的文章
returnHttpResponse(year)def year_month_archive(request,year,month): #无名分组时,year 和 month 的前后位置关系,必须和路由里的正则匹配时一样
#去数据库查询指定年、指定月份的文章
return HttpResponse("year:%s month:%s" %(year,month))def year_month_archive2(request,month,year): #有名分组时,year和month参数,顺序就可以打乱写了。
#去数据库查询指定年、指定月份的文章
return HttpResponse("year:%s month:%s" %(year,month))
# app01 的views.py
#app02 的views.py
from django.shortcuts importrender,HttpResponse#render是一个函数,HttpResponse是一个类
#Create your views here.
importtime,datetime#函数1 主页
defindex(request):return HttpResponse("app02 主页")#函数2 显示当前时间给前端
deftimer(request):
now=str(datetime.datetime.now())return HttpResponse("app02 当前时间:"+now)
# app02 的views.py
5. 反向解析 (可以理解为在路由分发时,使用 别名) ---- 别名在html文档里的应用
1.url路由里,设置 别名
2.视图函数里,执行render(request,'login.html')时,django将检索特殊语法,将html里的特殊语法进行替换
3.html文件 表单提交时的 url使用 {% url '别名' %},来替代直接写死的方式
4.当对外的接口发生变化时,需要修改的代码量就很少。使用浏览器访问如下:
------
6.反向解析 (可以理解为在路由分发时,使用 别名) ---- 别名在html文档里的应用2 (路由里包含分组的动态参数时)
在上面的正则中,没有分组的动态参数。当正则中含有分组的动态参数时,html里使用别名时,就必须配上对应的参数
7.反向解析 的另一应用场景 ----- 别名在views.py视图函数里的应用1
1.在urls.py里设置路径别名
2. 在views.py里,导入 reverse方法
from django.urls import reverse
8.反向解析 的另一应用场景 ----- 别名在views.py视图函数里的应用2
上面第7点,正则中没有分组的动态参数。
现在,如果正则里有分组的动态参数,则在views.py中,使用 reverse()时,必须传入 args=(参数1,参数2...)
总结:
路径使用别名的好处: 假如我们的视图函数、或者html模板中有用到路径,如果把路径写死成固定字符串,一旦后期对外接口发生变化,我们用到此路径的地方,也必须手动同步修改,维护难。使用别名,则很好的解决了这种问题。
--
--------