Django(7)url命名的作用
前言
为什么我们url需要命名呢?url命名的作用是什么?我们先来看一个案例
案例
我们先在一个Django项目中,创建2个App,前台front
和后台cms
,然后在各自app下创建urls.py
文件,创建成功后项目代码结构如下:
然后写入如下代码
# url_demo.urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('cms/', include('cms.urls')),
path('front/', include('front.urls')),
]
# front.urls.py
urlpatterns = [
path('', views.index),
path('login/', views.login),
]
# front.views.py
from django.shortcuts import render, redirect, reverse
from django.http import HttpResponse
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("front首页")
else:
return redirect('login/')
def login(request):
return HttpResponse('front登录页面')
上面代码我们实现的功能是:访问首页,如果没有携带username,那么重定向到登录页面,我们现在在浏览器中输入127.0.0,1/front/
,那么会自动重定向到login
登录页面,浏览器上会返回front登录页面
,我们可以从pycharm运行记录中看到
[14/May/2021 03:22:02] "GET /front/ HTTP/1.1" 302 0
[14/May/2021 03:22:02] "GET /front/login/ HTTP/1.1" 200 17
当我们在浏览器输入http://127.0.0.1:8000/front/?username=jkc
,浏览器会返回front首页
,此时,产品经理对你说:我们的登录url改一下,把login改成signIn,这时程序员A,就把urls.py
中的login
和views
中的重定向login/
改成了signIn
,改完后功能可以实现没问题,但是产品经理这几天反复的让A去改地址,那么程序员A每次都要去修改路由和视图2个地方,那么有没有什么方法可以只修改路由,答案肯定是有的,下面我我们来介绍
urls命名
我们就将front.urls.py
和views.py
改成下面的代码
# front.urls.py
urlpatterns = [
path('', views.index, name="index"),
path('signIn/', views.login, name="login"),
]
# front.views.py
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("front首页")
else:
return redirect(reverse('login'))
我们在路由地址中添加了一个name参数,代表路由的名字,然后在视图中使用反向解析函数reverse
将路由地址解析成为login
,意思是寻找路由名字为login的地址,这样处理,以后产品经理想改url地址,我们只需要修改url中的地址就可以了,因为视图中永远会反向解析到名字为login
的路由地址。
为什么我们需要url命名
答:因为url是经常变化的。如果在代码中写死可能会经常改代码。给url取个名字,以后使用url的时候就使用他的名字进行反转就可以了,就不需要写死url了。
但是我们这样url反转的时候还会有问题,我们来看下面代码
# cms.urls.py
urlpatterns = [
path('', views.index, name="index"),
path('login/', views.login, name="login")
]
# front.urls.py
urlpatterns = [
path('', views.index, name="index"),
path('signIn/', views.login, name="login"),
]
# cms.views.py
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("cms首页")
else:
return redirect(reverse('login'))
def login(request):
return HttpResponse('cms登录页面')
# front.views.py
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("front首页")
else:
return redirect(reverse('login'))
def login(request):
return HttpResponse('front登录页面')
我们在浏览器中输入127.0.0.1/cms/
,最后发现路由重定向到了front的登录页面,可以通过pycharm中的控制台看到
[14/May/2021 05:50:37] "GET /cms/ HTTP/1.1" 302 0
[14/May/2021 05:50:37] "GET /front/signIn/ HTTP/1.1" 200 17
原因是cms和front都有相同的index
路由,那么路由反转的时候,django无法辨别到底反转到哪个app下的index,此时我们就需要使用应用命名空间
,在各自app的urls.py文件中添加app_name
属性,值为App的名字,代码如下
# cms.urls.py
app_name = "cms" # 应用命名空间
urlpatterns = [
path('', views.index, name="index"),
path('login/', views.login, name="login")
]
# front.urls.py
app_name = "front" # 应用命名空间
urlpatterns = [
path('', views.index, name="index"),
path('signIn/', views.login, name="login"),
]
# cms.views.py
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("cms首页")
else:
return redirect(reverse('cms:login'))
def login(request):
return HttpResponse('cms登录页面')
# front.views.py
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("front首页")
else:
return redirect(reverse('front:login'))
def login(request):
return HttpResponse('front登录页面')
上述代码我们从之前的基础上改成了reverse('front:login')
,这样django就知道了我是反转front
app下的路由名字为login
的url
一个app,可以创建多个实例。可以使用多个url映射同一个app。所以这就会产生一个问题。以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆。为了避免这个问题。我们可以使用实例命名空间。实例命名空间也是非常简单,只要在include
函数中传递一个namespace
变量即可。示例代码如下:
urlpatterns = [
path('cms1/', include('cms.urls', namespace="cms1")),
path('cms2/', include('cms.urls', namespace="cms2")),
]
此时我们浏览器访问127.0.01/cms2/
,却重定向到了cms1的login页面,我们可以通过pycharm的控制台看到
[14/May/2021 06:53:07] "GET /cms1/ HTTP/1.1" 302 0
[14/May/2021 06:53:07] "GET /cms2/login/ HTTP/1.1" 200 15
[14/May/2021 06:53:12] "GET /cms2/ HTTP/1.1" 302 0
[14/May/2021 06:53:12] "GET /cms2/login/ HTTP/1.1" 200 15
以后在做反转的时候,就可以根据实例命名空间来指定具体的url。示例代码如下:
def index(request):
username = request.GET.get('username')
if username:
return HttpResponse("cms首页")
else:
# 获取当前实例命名空间
current_namespace = request.resolver_match.namespace
return redirect(reverse(f'{current_namespace}:login'))
然后我们通过浏览器访问127.0.01/cms2/
,结果就是正确的,我们可以通过pycharm的控制台看到
[14/May/2021 07:02:20] "GET /cms1/ HTTP/1.1" 302 0
[14/May/2021 07:02:20] "GET /cms1/login/ HTTP/1.1" 200 15
[14/May/2021 07:02:25] "GET /cms2/ HTTP/1.1" 302 0
[14/May/2021 07:02:25] "GET /cms2/login/ HTTP/1.1" 200 15