路由基础、多app共存,路由分配、路由分发(将app自己的路由分发给应用自身管理)、反解
一:路由基础
1.路由自上而下进行匹配
2.url(正则路径,视图函数内存地址,默认参数,路由别名)
Django服务开启后,打开浏览器,输入url地址,向服务器发送请求,此时服务器拿到当前请求的url地址(例如:http://127.0.0.1:8801/index),Django通过对项目中的urls模块进行配置,对请求拿到的url地址进行解析,分发至对应的函数中,完成业务逻辑,实现功能。
在urls模块中的 urlpatterns列表中存放着正则路径,视图函数地址,默认关键字参数(可选),路由别名(可选)。
有一个url地址 http://127.0.0.1:8801/login,需要执行的是页面的登录功能,那么在对应的功能模块(app)的views存放着实现这个登录功能的login函数,那么有以下几种可以匹配到此功能的路由写法:
1.功能参数不需要传参
# url(r'^login$', views.login) 只能匹配login,不能匹配index/ # url(r'^login/$', views.login)能匹配login/,也能匹配login(先拿index匹配,如果失败,会添加/再次匹配) 在settings中添加APPEND_SLASH = False 会导致Django不会自动添加/,也可以将settings中将'django.middleware.common.CommonMiddleware' 注释掉
2.功能参数需要传参
#url(r'^login/$', views.login, {'num': 88888}) 此处为关键字参数 #功能函数为如下: def login(request,num): pass
二:路由正则
1.规定开始:^ | 规定结束:$ url(r'index', views.index) => /index/ | /aindex/ | /indexb/ | /aindexb/ 均能匹配 url(r'^index', views.index) => /index/ | /indexb/ 能匹配 url(r'^index/$', views.index) => /index/ 才能匹配 2.无名分组:^delete/(\d+)/(\d+)$ 路由:url(r'^delete/(\d+)/(\d+)$', views.delete) 请求路径:/delete/1/2 视图函数:def delete(request, n1, n2) => n1可以拿到请求路径中的1,n2拿到2 3.有名分组:^delete/(?P<id>\d+)/(?P<num>\d+)$ 请求路径:/delete/1/2 视图函数:def delete(request, id, num) => 只能用id,num变量接收1、2 注:路由正则不支持有名无名分组混用
三:有名无名分组
在我们平时浏览网页的时候会发现在一些网址后后面后添加着一些数字(我们将这些页面称之为子页面,这些数字可能是为功能函数提供某个参数,或者是数据库中的某个数据的一个数据),例如:http:www.xxx.xxx/1/2,那么这种句子的匹配应该如何匹配呢,这就需要使用到有名无名分组
了。
# 无名分组:/testnoname/10/ url(r'^testnoname/(\d+)/$', views.testnoname) # def testnoname(request, var) # var=10 # 有名分组:/testname/10/1/ url(r'^testname/(?P<num>\d+)/(?P<page>\d+)/$', views.testname) # def testname(request, page, num) # page=1 num=10 # 注:不能混用
无名分组: url(r'^login/(\d+)$',views.login) #功能函数为: def login(request,var): print(var) return render(request,'login.html')
#最终对应的url如下:http://127.0.0.1:8802/10/20,有名分组与其一致,不过在有名分组中多个参数,在功能函数中只按名字对应,位置前后不会影响
值的顺序。
运行服务器,在浏览器中输入http://127.0.0.1:8802/login/10/这个地址之后,会成功跳转至登录页面,并且在login函数中传入10这个值。
有名分组: url(r'^login/(?P<num>(\d+))$',views.login) #功能函数为: def login(request,num): print(num) return render(request,'login.html') #注意:有名分组中的num名字必须与函数中的参数名对应,否则会参数错误
四:多app共存的路由分配
在主路由中要配置多个app,要对视图函数调用起别名 from app01 import views as app01_views from app02 import views as app02_views url(r'^app01/test_page/$', app01_views.test_page), url(r'^app02/test_page/$', app02_views.test_page),
多个app的创建过程
1.创建多个应用:django-admin startapp app_name | python3 manage.py startapp app_name | Tools工具 2.在settings.py中配置INSTALLED_APPS,添加新建的应用:'app_name.apps.App_nameConfig'
在一个Django中会出现多个功能模块,那么每个app都对应着一个views模块,在里面写着各自的功能代码,有时两个功能模块可能会出现两个名字一致的函数,但是他们实现的功能却是不一致的,如何解决这个问题呢?
import app01.views as app01_views import app02.views as app02_views urlpatterns = [ url(r'^app01/test/$', app01_views.test), url(r'^app02/test/$', app02_views.test), ] #在导入模块中,将每个不同功能的views模块起一个不同的名字,并且url地址也要加上对应的功能模块名,一一对应,即使用方便,也不会出现多app的路由冲突。
五:多app共存时模板冲突问题
方法1:在对应应用下建立自己的templates,再在templates下建立与应用名同名的文件夹,模板文件放在应用名同名的文件夹下 方法2:在项目根目录下的templates中建立每一个应用同名的文件夹,每个应用的模板文件放在自己应用名文件夹下 使用:render(request, 'app_name/test.html')
六:创建app流程
1. python3 manage.py startapp app_name 2. 去settings中配置INSTALLED_APPS, 添加记录:'app_name.apps.App_nameConfig' # 注:app配置的顺序决定了(共同资源冲突下的)查找顺序
七:路由分发
# 分担总路由的代码压力, 将每个app的自身路由配置交给app自己的ulrs.py来管理(分文件管理路由) 1.在每一个应用中建立自身的urls.py文件,语法同主路由 2.在主路由进行分发 from django.conf.urls import include urlpatterns = [ url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ] # 注:主路由分发一定不能使用$正则语法 (错误eg: ^app01/$)
八:路由别名
1.有些路由会被大量访问(直接访问、间接访问) 2.这些路由可能后期还会发生变化 3.可以给路由设置别名,通过别名访问:<a href="{% url '路由别名' '传入有名无名分组所需参数' %}"></a>
九:名称空间
主路由: from django.conf.urls import include urlpatterns = [ url(r'^app01/', include('app01.urls', namespace='app01')), url(r'^app02/', include('app02.urls', namespace='app02')), ] app01应用下路由 from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^test/', views.test, name='test') ] app02应用下路由 from django.conf.urls import url from app02 import views urlpatterns = [ url(r'^test/', views.test, name='test') ] 前端页面反向解析:{% url 'app01:test' %} | {% url 'app02:test' %} 视图函数reverse方法:url = reverse('app01:test') | url = reverse('app02:test')
十:反向解析
from django.shortcuts import reverse 在视图函数中通过reverse方法反向解析出真实的路径 # 1.不带分组:url(r'可能会变的真实路由', 视图函数, name='路由别名') url = reverse('路由别名') # 2.无名分组:url(r'可能会变的真实路由(带无名分组)', 视图函数, name='路由别名') url = reverse('路由别名', args=(给无名分组赋值)) # 3.有名分组:url(r'可能会变的真实路由(带有名分组)', 视图函数, name='路由别名') url = reverse('路由别名', kwargs={给有名分组赋值,key就是有名分组名})
十一:2.x新特性
from django.urls import path, re_path # 向下兼容,不建议使用url, 使用与url相同的re_path from django.conf.urls import url urlpatterns = [ path('index/', views.index), # page/<int:msg>/ page/(?P<msg>(\d+)) # 访问/page/123/ # path('page/<int:msg>/', views.page), # path('page/<str:msg>/', views.page), # path('page/<path:msg>/', views.page), # path('page/<slug:msg>/', views.page), path('page/<uuid:msg>/', views.page), ] # 1. 2.x版本re_path的使用方式同1.x版本url # 2. path写的是绝对字符串,请求地址必须与路由地址完全匹配 # 3. path拥有五个转换器: -- str:匹配除路径分隔符(/)外的字符串,默认 -- int:匹配自然数 -- slug:匹配字母、数字、横杠及下划线组成的字符串 -- uuid:匹配uuid形式的数据 -- path:匹配任何字符串,包括路径分隔符(/) (不能用?)
十二:自定义转换器
# 原因:自定义正则匹配目标路径 语法: 1.自定义类 # 匹配11位的185电话 class CVT185phone: # 匹配过程 regex = '185\d{8}' def to_python(self, value): return int(value) # 反解过程 def to_url(self, value): return '%11d' % value # 在主路由中 from django.urls import register_converter from 所在路径 import CVT185phone register_converter(CVT185phone, 'phone185') path('page/<phone185:msg>/', views.page, name="pages")