参考博客: https://www.cnblogs.com/yuanchenqi/articles/8876685.html
Django路由
1.简单的路由配置
from django.contrib import admin from django.urls import path, re_path # django 2.往后的版本,要使用正则,需要引入re_path # 必须导入自己创建的应用里的views视图.py文件 from app01 import views 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 import admin from django.urls import path, re_path # django 2.往后的版本,要使用正则,需要引入re_path # 必须导入自己创建的应用里的views视图.py文件 from app01 import views 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 import render,HttpResponse #render是一个函数,HttpResponse是一个类 # Create your views here. import time,datetime def special_year(request): # 去数据库查询所有2003年的文章 return HttpResponse("special_year:2003 OK") def year_archive(request,year): #这里的year拿到的是 字符串类型 # 去数据库查询所有指定年份的文章 return HttpResponse(year) def year_month_archive(request,year,month): # 去数据库查询指定年、指定月份的文章 return HttpResponse("year:%s month:%s" %(year,month))
使用浏览器访问:
-----
----
3.有名分组 (对比上面的无名分组)
- 正则里使用 ( ) 进行分组
- 使用 ?P< 关键字> 来给该分组起名字
urls.py如下:
from django.contrib import admin from django.urls import path, re_path # django 2.往后的版本,要使用正则,需要引入re_path # 必须导入自己创建的应用里的views视图.py文件 from app01 import views 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<year>\d{4})/(?P<month>\d{2})/$", views.year_month_archive2), # year_archive2(request,year=\'2020\',month=\'01\') ]
views.py如下:
from django.shortcuts import render,HttpResponse #render是一个函数,HttpResponse是一个类 def special_year(request): # 去数据库查询所有2003年的文章 return HttpResponse("special_year:2003 OK") def year_archive(request,year): # 去数据库查询所有指定年份的文章 return HttpResponse(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 import path, 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的路由里 ]
4.2 各应用的 urls.py (需要自己创建该.py文件。可以直接复制全局的代码过来,稍作修改)
app01的urls.py:
app02的urls.py:
app_index的 urls.py:
# app01的urls.py from django.contrib import admin from django.urls import path, re_path # django 2.往后的版本,要使用正则,需要引入re_path # 必须导入自己创建的应用里的views视图.py文件 from app01 import views 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<year>\d{4})/(?P<month>\d{2})/$", views.year_month_archive2), # year_archive2(request,year=\'2020\',month=\'01\') ]
# app02的 urls.py from django.contrib import admin from django.urls import path, re_path # django 2.往后的版本,要使用正则,需要引入re_path # 必须导入自己创建的应用里的views视图.py文件 from app02 import views urlpatterns = [ re_path("^$",views.index), # 分发到 应用app02的首页 re_path("^timer/$",views.timer), ]
# app_index 的 urls.py from django.contrib import admin from django.urls import path, re_path # django 2.往后的版本,要使用正则,需要引入re_path # 必须导入自己创建的应用里的views视图.py文件 from app_index import views urlpatterns = [ re_path("^$", views.index), #发到 应用app_index的首页,此示例,把此应用的首页,作为整个项目的首页 ]
4.3 各应用的 views.py
4.4 使用浏览器访问:
==
==
==
# app_index的views.py from django.shortcuts import render,HttpResponse #render是一个函数,HttpResponse是一个类 # Create your views here. # 函数1 主页 def index(request): return HttpResponse("项目 主页")
# app01 的views.py from django.shortcuts import render,HttpResponse #render是一个函数,HttpResponse是一个类 # Create your views here. import time,datetime def special_year(request): # 去数据库查询所有2003年的文章 return HttpResponse("special_year:2003 OK") def year_archive(request,year): # 去数据库查询所有指定年份的文章 return HttpResponse(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))
# app02 的views.py from django.shortcuts import render,HttpResponse #render是一个函数,HttpResponse是一个类 # Create your views here. import time,datetime # 函数1 主页 def index(request): return HttpResponse("app02 主页") # 函数2 显示当前时间给前端 def timer(request): now=str(datetime.datetime.now()) return HttpResponse("app02 当前时间: "+now)
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模板中有用到路径,如果把路径写死成固定字符串,一旦后期对外接口发生变化,我们用到此路径的地方,也必须手动同步修改,维护难。使用别名,则很好的解决了这种问题。
--
--------