文章目录
1. 项目目录
这一节我们需要在原有的目录下,创建 models/urls.py
,在各自的APP下完成路由的一些操作
2. 路由分发
存在问题:
Django 项目里多个app目录共用一个 urls 容易造成混淆,后期维护也不方便
解决:
使用路由分发(include),让每个app目录都单独拥有自己的 urls
步骤:
- 在每个 app 目录里都创建一个
urls.py
文件。 - 在项目名称目录下的 urls 文件里,统一将路径分发给各个
app
目录
2.1 全局路径分发到APP
在项目的根目录下 myFirstDjango/urls.py
中填写路由分发规则
from django.urls import path, include # 从 django.urls 引入 include
# 此项就是django的url配置
"""
path('models/', include('models.urls')) include 路由分发
相当于flask框架的蓝图,把请求分开到不同的app中,方便后期维护
models/ : 相当于访问项目时根路径下一层的请求名字 http://localhost:8080/models/
注意必须添加最后的 / 不然路径不通
include('models.urls') : 引入了 models APP中的 urls.py文件,这样的话django框架
就知道去哪里找你的映射路径了,浏览器输入http://localhost:8080/models/XXX
django就会去 models/urls.oy去找你的下一层请求地址
"""
urlpatterns = [
path('models/', include('models.urls'))
]
2.2 APP定义自己的路由转发规则
在 models/urls.py
中写自己APP的路由规则即可
from django.urls import path
# 路由分发就每个模块都引入自己的 urls.py 和 views.py 文件
from models import views # 在models APP中 引入的 models/views.py
# 此项就是django的url配置
"""
path('url_include', views.url_include)
path('url_include' : 这里的 url_include 是第二层路径的名称
views.url_include) : 第一个参数路径名称指向的视图函数是 views.py/url_include 函数
第一层/第二层
完整路径为 : http://localhost:8080/models/url_include
"""
urlpatterns = [
path('url_include', views.url_include),
]
在 models/views.py
中添加如下代码
from django.shortcuts import HttpResponse
def url_include(request):
return HttpResponse("我是models下的urls.py 经过路由分发转发过来的请求视图")
浏览器输入完整路径 http://localhost:8080/models/url_include
可以看到浏览器路径不是从根路径就下发请求,中间定义了一个models,这就是路由分发,通过不同APP的urls 和 views,可以定义不同的路径分发规则,不再是所有的代码都写在一个文件里了,后期维护非常的方便
3. 反向解析
随着功能的增加,路由层的 url 发生变化,就需要去更改对应的视图层和模板层的 url,非常麻烦,不便维护这时我们可以利用反向解析,当路由层 url 发生改变,在视图层和模板层动态反向解析出更改后的 url,免去修改的操作,反向解析一般用在模板中的超链接及视图中的重定向
3.1 视图反向解析
在 models/urls.py
修改为以下内容
urlpatterns = [
path('url_include', views.url_include),
# 添加名称,不管 path的地址怎么变,都能通过 login这个名字反向解析到视图函数中
path('to_login', views.login, name='login'),
]
在 models/views.py
修改为以下内容
from django.shortcuts import HttpResponse, redirect
from django.urls import reverse
def url_include(request):
"""
到达这个视图函数后,只做一个重定向操作
重定向地址为 : login 这是使用反向解析的名称
:param request:
:return:
"""
return redirect(reverse('login'))
def login(request):
"""
重定向到 login 这个名称
名称所对应的视图函数为 login
不管path 后的第一个参数如何变化,都能正确的重定向到此函数中
:param request:
:return:
"""
return HttpResponse("通过反向解析指向了这个视图函数")
在浏览器输入 http://localhost:8080/models/url_include
重定向到login视图函数中
可以看到地址 models后面为 to_login
,这是path后的名称,我们并没有指定地址,只是指定了一个重定向的login名字,他就会自己反向解析到 models/login
视图函数中
更改 models/urls.py
的路由规则
urlpatterns = [
path('url_include', views.url_include),
# 更改 to_login 名称为 asdfsadfsd ,看看能不能正确转发到视图函数中
path('asdfsadfsd', views.login, name='login'),
]
重启服务,在浏览器输入 http://localhost:8080/models/url_include
可以看到还是正确的转发到了相对应的视图函数中,但是我们的代码并没有更改,只不过地址栏的名称变成了 models/asdfsadfsd
,这就是反向解析的好处
在模板 templates 中的 HTML 文件中,利用 {% url "路由别名" %}
反向解析
<form action="{% url 'login' %}" method="post">
3.2 正则路径(无名参数)
所谓的无名参数指的就是 参数没有指定名称,只需要按照正则表达式的规则按照顺序传参即可匹配到正确的视图函数中
在 models/urls.py
中修改为以下内容
from django.urls import path,re_path
# 路由分发就每个模块都引入自己的 urls.py 和 views.py 文件
from models import views # 在models APP中 引入的 models/views.py
# 此项就是django的url配置
urlpatterns = [
path('url_include', views.url_include),
# 正则表达式无名参数分组,这里的无名指的就是传的参数没有名称,只是按照位置顺序传参
# login/ 0-9 两位数的参数/
re_path(r"^login/([0-9]{2})/$", views.login, name="login")
]
在 models/views.py
中修改为以下内容
# Create your views here.
from django.shortcuts import HttpResponse, redirect
from django.urls import reverse
def url_include(request):
"""
到达这个视图函数后,只做一个重定向操作
重定向地址为 : login 这是使用反向解析的名称
args=(10,) : 正则表达式为无名参数,那么需要按照顺序来传参 10为参数
只能通过正确的匹配路由规则才能成功匹配到正确的视图函数中
:param request:
:return:
"""
return redirect(reverse('login', args=(10,)))
def login(request, num):
"""
函数中必须写接受参数的变量名称,不然会报错 ,这里用num接收
:param request:
:return:
"""
return HttpResponse("无名参数重定向到此视图函数中,参数为 : {}".format(num))
在浏览器中输入地址 http://localhost:8080/models/url_include
,即可看到匹配到正确的视图函数中
在模板 templates 中的 HTML 文件中利用 {% url "路由别名" 符合正则匹配的参数 %}
反向解析
<form action="{% url 'login' 10 %}" method="post">
3,3 正则路径(有名参数)
所谓的有名参数指的就是 参数有指定的名称,传参需要按照键值对的方式指定参数,有名分组按关键字传参,与位置顺序无关
语法: (?P<组名>正则表达式)
在 models/urls.py
中修改为以下内容
from django.urls import path,re_path
# 路由分发就每个模块都引入自己的 urls.py 和 views.py 文件
from models import views # 在models APP中 引入的 models/views.py
urlpatterns = [
path('url_include', views.url_include),
# login/ 0-9 四位数的参数,名称为 year /
re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")
]
在 models/views.py
中修改为以下内容
from django.shortcuts import render
# Create your views here.
from django.shortcuts import HttpResponse, redirect
from django.urls import reverse
def url_include(request):
"""
kwargs={"year": 2020} : 给名称为 year 的参数赋值 2020
正则表达式有名参数,有名分组按关键字传参,与位置顺序无关
:param request:
:return:
"""
return redirect(reverse('login', kwargs={"year": 2020}))
def login(request, year):
"""
函数中必须写接受参数的变量名称,而且名称必须和有名参数一致为year!,不然报错
:param request:
:return:
"""
return HttpResponse("有名参数重定向到此视图函数中,参数为 : {}".format(year))
在浏览器中输入地址 http://localhost:8080/models/url_include
,即可看到匹配到正确的视图函数中
在模板 templates 中的 HTML 文件中利用 {% url "路由别名" 分组名=符合正则匹配的参数 %}
反向解析
<form action="{% url 'login' year=2020 %}" method="post">
4. 命名空间
解释:
- 命名空间(英语:Namespace)是表示标识符的可见范围。
- 一个标识符可在多个命名空间中定义,它在不同命名空间中的含义是互不相干的
- 一个新的命名空间中可定义任何标识符,它们不会与任何重复的标识符发生冲突,因为重复的定义都处于其它命名空间中
存在问题:
路由别名 name 没有作用域,Django 在反向解析 URL 时,会在项目全局顺序搜索,当查找到第一个路由别名 name 指定 URL 时,立即返回,当在不同的 app 目录下的urls 中定义相同的路由别名 name 时,可能会导致 URL 反向解析错误
解决:
使用命名空间
4.1 普通路径
定义命名空间(include 里面是一个元组)格式如下:
include(("app名称.urls","app名称"))
在 myFirstDjango/urls.py
进行路由分发的时候,指定命名空间
from django.urls import path, include # 从 django.urls 引入 include
# 此项就是django的url配置
"""
path('models/', include(('models.urls', "models"))) include 路由分发
相当于flask框架的蓝图,把请求分开到不同的app中,方便后期维护
models/ : 相当于访问项目时根路径下一层的请求名字 http://localhost:8080/models/
注意必须添加最后的 / 不然路径不通
include(('models.urls', "models")) : 指定models.urls的命名空间为 models
指定后的好处是,在进行重定向或其他使用别名的反向解析操作中
可以指定命名空间下的别名路径,这样django就会去你指定的那个APP下
寻找了,这样就避免了URL反向解析错误
"""
urlpatterns = [
# 注意 include中参数格式是元组
path('models/', include(('models.urls', "models")))
]
在 models/urls.py
中修改内容如下
from django.urls import path,re_path
# 路由分发就每个模块都引入自己的 urls.py 和 views.py 文件
from models import views # 在models APP中 引入的 models/views.py
# 此项就是django的url配置
"""
path('url_include', views.url_include)
path('url_include' : 这里的 url_include 是第二层路径的名称
views.url_include) : 第二个参数为 第一个参数路径名称 指向的视图函数是 views.py/url_include
第一层/第二层
完整路径为 : http://localhost:8080/models/url_include
"""
urlpatterns = [
path('url_include', views.url_include),
# login/ 0-9 四位数的参数,名称为 year /
re_path(r"^login/(?P<year>[0-9]{4})/$", views.login, name="login")
]
在 models/views.py
中 ,修改内容如下
from django.shortcuts import HttpResponse, redirect
from django.urls import reverse
def url_include(request):
"""
models:login : 指定重定向到 models下的别名login路由规则中,而不是其他APP
:param request:
:return:
"""
return redirect(reverse('models:login', kwargs={"year": 2020}))
def login(request, year):
"""
函数中必须写接受参数的变量名称,而且名称必须和有名参数一致为year!,不然报错
:param request:
:return:
"""
return HttpResponse("有名参数重定向到此视图函数中,参数为 : {}".format(year))
在浏览器输入 http://localhost:8080/models/url_include
依然会正确解析到对应的视图函数中,这里我们指定了命名空间,避免不同APP之间路由别名相同,URL反向解析错误的问题
在 templates 模板的 HTML 文件中使用名称空间,语法格式如下:
{% url "app名称:路由别名" %}
实例
<form action="{% url 'models:login' %}" method="post">
https://www.runoob.com/django/django-routers.html