标签:额外 使用 ESS list pychar 技术分享 完成后 code cdc
转载请注明来源地址和原作者(CFishHome)上一篇文章我们学习了URL与视图函数的映射、传递参数的三种方式、转换器的简单使用和include函数分层映射管理。接下来这一篇文章着重介绍Path、re_path、include、reverse、redirect函数的使用和自定义URL转换器。学完这些内容,相信我们对URL和视图都会有了一定的了解和认识。为了让每篇文章具有一定的独立性,我决定每篇文章都重新新建一个项目,便于测试和调试。
首先,我们在Pycharm重新新建一个名为book_project的Django项目,然后打开CMD窗口进入虚拟环境,接着跳转到该项目的目录下(含有manage.py),再依次执行创建app命令,如下图:
创建完成后,该项目的样子大概是酱紫的:
我们想实现:front前端拥有前端首页和前端登陆页面,而cms后端拥有后端首页和后端登陆页面,然后分别输入配置好的URL对这四个页面进行访问。
首先,为cms和front两个app手动添加urls.py文件。然后分别按以下步骤添加或修改项目文件代码:
(1)为cms的urls.py文件添加以下代码:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index),
path("login/", views.login)
]
(2)为front的urls.py文件添加以下代码:
from django.urls import path
from . import views
urlpatterns = [
path("", views.index),
path("login/", views.login)
]
(3)为cms的views.py文件添加以下代码:
from django.http import HttpResponse
def index(request):
return HttpResponse("后端首页")
def login(request):
return HttpResponse("后端登陆页面")
(4)为front的views.py文件添加以下代码:
from django.http import HttpResponse
def index(request):
return HttpResponse("前端首页")
def login(request):
return HttpResponse("前端登陆页面")
(5)为book_project这个主包的urls.py文件添加以下代码:
from django.urls import path,include
urlpatterns = [
path(‘‘, include("front.urls")),
path(‘cms/‘, include("cms.urls"))
]
如果学习了上一篇文章的内容,我相信这些代码的编写是完全OK的。好,我们运行一下项目(注意,我们是新建的项目,记得在勾选单一实例运行。)。
运行结果如下(完美,成功运行~):
实际需求:要想实现一个类似于知乎主页一样,若是新用户第一次登陆知乎,不管哪个页面都会跳转到登陆账号的页面,对于这一需求,我们可以通过以下模拟实现(为了更好观察代码,一样的代码部分我直接提示省略):
(1)修改front前台的index视图函数
#省略上面代码
from django.shortcuts import redirect # 导入重定向redirect函数,最好记住redirect函数源于哪个模块,因为要经常重定向。
def index(request):
# ?username=xxx
username = request.GET.get(‘username‘) # 当用户输入127.0.0.1:8000,检测到没有账户则跳转到注册页面,当输入http://127.0.0.1:8000/?username=1正常显示前台首页。
if username:
return HttpResponse(‘前台首页‘)
else:
return redirect(‘/login/‘) # 跳转通过redirect函数来进行页面重定向,重新访问指定的url页面
#省略下面代码
修改完代码后,按下Ctrl+S保存(自动重新编译项目)。注意观察,输入127.0.0.1:8000会发现自动跳转到127.0.0.1:8000/login/。
其实还存在这样一种情况,假如老板或项目经理突然脑袋秀逗了,要求你更改网页的URL,将127.0.0.1:8000/login/更改为127.0.0.1:8000/signin/,假如这时还采用上面的代码进行网页重定向,那你会非常抓狂,举我们这个项目栗子来说,不单只要修改为下面这样:
urlpatterns = [
path("", views.index),
path("signin/", views.login)
]
还要修改重定向位置的代码这样:
def index(request):
# ?username=xxx
username = request.GET.get(‘username‘) # 当用户输入127.0.0.1:8000,检测到没有账户则跳转到注册页面,否则正常显示前台首页。
if username:
return HttpResponse(‘前台首页‘)
else:
return redirect(‘/singin/‘) # 跳转通过redirect函数来进行页面重定向,重新访问指定的url页面
如果公司网站项目十分庞大的话,那可能还有很多地方都要修改,这十分耗时也费力。所以,我们推荐为URL命名来解决这一问题,给URL取个名字,只要调用reverse反转URL的名字而不是直接重定向写死的URL,那么无论URL怎么修改也影响不到其他地方。
在学习URL命名之前,先详细学习下Path函数的使用。
path 函数的定义为:
path(route,view,name=None,kwargs=None) 。
以下对这几个参数进行讲解。
from django.urls import path
from . import views
urlpatterns = [
path(‘blog/<int:year>/‘, views.year_archive, kwargs={‘foo‘:‘bar‘}),
]
那么以后在访问 blog/1991/ 这个url的时候,会将{‘foo‘:‘bar‘}作为关键字参数传给 year_archive函数。year_archive视图函数的形参中最后添加一个kwargs参数来接收这个额外的参数。
学习完path函数各参数,相信都知道该函数的name参数就是用于URL命名的了。
接下来修改front包的urls.py文件代码如下:
urlpatterns = [
path("", views.index),
path("login/", views.login, name=‘login‘)
]
再次修改front包的views.py文件代码如下:
#省略上面代码
from django.shortcuts import redirect, reverse # 注意这里添加了reverse函数,reverse函数用于将指定URL名字反转成URL。
def index(request):
# ?username=xxx
username = request.GET.get(‘username‘) # 当用户输入127.0.0.1:8000,检测到没有账户则跳转到注册页面,否则正常显示前台首页。
if username:
return HttpResponse(‘前台首页‘)
else:
# reverse(‘login‘)函数返回‘/login/’
return redirect(reverse(‘login‘)) # 跳转通过redirect函数来进行页面重定向,重新访问指定的url页面(相当于重新访问127.0.0.1:8000/login/)
#省略下面代码
按下Ctrl+S保存,输入127.0.0.1:8000成功跳转到127.0.0.1:8000/login登陆页面。
在公司实际开发中,如果公司里的多个人同时负责网站的开发,而且A同事负责开发front的app,B同事负责开发cms的app,那么由于两个app都有首页和登陆页面,那么有可能url的name属性可能会相同冲突。在多个app之间,有可能产生同名的url,这时候为了避免反转url的时候产生混淆,可以使用应用命名空间来做区分。定义应用命名空间非常简单,只要在“app”的“urls.py”中定义一个叫做“app_name”的变量,来指定这个应用的命名空间即可。
就好比我们的项目,将front包里的urls.py和views.py文件和cms包里的urs.py和views.py文件分别为URL映射命名为index和login,如下图所示:
运行项目,输入127.0.0.1:8000自动跳转到127.0.0.1:8000/cms/login网页,而不是之前的127.0.0.1:8000/login网页,由于多个app的URL拥有相同的名字,所以Django在执行reverse函数反转URL时懵逼了。为了解决这个问题,我们将采用应用命名空间。
修改front包的urls.py文件的代码如下(django在执行到app时,会自动读取这个应用命名空间并将这个名字作为app的名字):
from django.urls import path
from . import views
app_name = "front" # 添加了应用命名空间
urlpatterns = [
path("", views.index, name="index"),
path("login/", views.login, name=‘login‘)
]
以后在做反转的时候就可以使用“应用命名空间:url名称”的方式进行反转。示例代码如下修改front包的views.py文件的代码如下:
def index(request):
# ?username=xxx
username = request.GET.get(‘username‘) # 当用户输入127.0.0.1:8000,检测到没有账户则跳转到注册页面,否则正常显示前台首页。
if username:
return HttpResponse(‘前台首页‘)
else:
return redirect(reverse(‘front:login‘)) # 这里为URL名字前面添加front应用命名空间名
按下Ctrl+S保存,输入127.0.0.1:8000自动跳转到127.0.0.1:8000/login网页,成功了,Django不会再懵逼了。
在上一篇文章我们知道,在项目不断庞大以后,经常不会把所有的 url 匹配规则都放在项目的 urls.py 文件中,而是每个 app 都有自己的 urls.py 文件,在这个文件中存储的都是当前这个 app 的所有url 匹配规则。然后再统一include到项目的 urls.py 文件中。 include 函数有多种用法,这里讲下几种常用的用法:
(1)include(pattern,namespace=None) :直接把其他 app 的 urls 包含进来。
之前的include用法,举个栗子(下面的代码仅用于解释用法,不是将代码添加到项目):
from django.contrib import admin
from django.urls import path,include
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘book/‘,include("book.urls"))
]
我们可以发现这一种用法其实该函数还有参数2指定实例命名空间,默认是None。但是在使用实例命名空间之前,必须先指定一个应用命名空间,不先指定应用命名空间会报错。一个app可以创建多个实例,也就是可以使用多个url映射同一个app,所以这就产生一个问题。以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆。
将book_project主包的urls.py文件代码修改如下:
from django.urls import path,include
urlpatterns = [
path(‘‘, include("front.urls")),
path(‘cms1/‘, include("cms.urls")), # 这两行代码代表输入127.0.0.1:8000/cms1或127.0.0.1:8000/cms2能映射到cms.urls内部的url路径。
path(‘cms2/‘, include("cms.urls"))
]
为cms包的urls.py文件添加应用命名空间:
app_name = "cms"
为cms包的views.py文件修改代码如下:
def index(request):
# ?username=xxx
username = request.GET.get(‘username‘) # 当用户输入127.0.0.1:8000,检测到没有账户则跳转到注册页面,否则正常显示前台首页。
if username:
return HttpResponse(‘后台首页‘)
else:
return redirect(reverse(‘cms:login‘)) # 这里使用了应用命名空间反转URL
经过上面代码的修改,这时候按下Ctrl+S保存,输入127.0.0.1:8000/cms1成功跳转到127.0.0.1:8000/cms1/login,但是当输入127.0.0.1:8000/cms2却自动跳转到了127.0.0.1:8000/cms1/login,what?我的127.0.0.1:8000/cms2/login哪里去了?导致上面的原因就是前面介绍的一个app可以创建多个实例,也就是可以使用多个url映射同一个app,所以这就产生一个问题。以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆。为了避免这个问题,我们可以使用实例命名空间。实例命名空间也是非常简单,只要在“include”函数中传递一个“namespace”变量即可。
在上面代码的基础上继续修改代码,修改cms包的views.py文件代码如下:
def index(request):
username = request.GET.get(‘username‘)
if username:
return HttpResponse("后端首页")
else:
current_namespace = request.resolver_match.namespace # 返回当前app对应的实例命名空间(cms1或cms2)
return redirect(reverse(‘%s:login‘ % current_namespace)) # 相当于"cms1:login"或”cms2:login“
接着修改book_project主包的urls.py文件代码如下:
from django.urls import path,include
urlpatterns = [
path(‘‘, include("front.urls")),
path(‘cms1/‘, include("cms.urls", namespace="cms1")), # 使用了实例命名空间namespace
path(‘cms2/‘, include("cms.urls", namespace="cms2"))
]
这时候按下Ctrl+S保存,输入127.0.0.1:8000/cms1成功跳转到127.0.0.1:8000/cms1/login,然后输入127.0.0.1:8000/cms2也成功跳转到了127.0.0.1:8000/cms2/login页面。如下图:
(2)include((pattern_list,app_namespace),namespace=None) :“include”函数的第一个参数既可以作为一个字符串,也可以作为一个元组,如果是元组,那么元组的第一个参数是子“urls.py”模块的字符串,元组的第二个参数是应用命名空间,也就是说应用命名空间既可以在子“urls.py”种通过"app_name"指定,也可以在“include”函数中指定。
将book_project主包的urls.py文件代码修改如下:
from django.urls import path, include
from front import views
urlpatterns = [
path(‘‘, include(([
path(‘‘, views.index, name="index"),
path("login/", views.login, name=‘login‘)
], "front"))), # 注意
path(‘cms1/‘, include("cms.urls", namespace="cms1")),
path(‘cms2/‘, include("cms.urls", namespace="cms2"))
]
上面的代码相当于完全忽略了front包的urls.py文件的作用,因为已经被include函数的第一个参数列表给替代了,所以urls.py文件的“app_name = "front"”指定的应用命名空间自然也失效了。这时运行代码完全OK,跟之前的一摸一样,输入127.0.0.1:8000自动跳转到127.0.0.1:8000/login页面。
(3)include(pattern_list) :可以包含一个列表或者一个元组,这个元组或者列表中又包含的是 path 或者是 re_path 函数(该函数后面会讲)。
这个函数跟上一个函数差不多,也是用含有path函数的列表或元组替代了之前的pattern。但是需要注意的是,因为这样会忽略了front包的urls.py文件的作用,所以urls.py文件的“app_name = "front"”指定的应用命名空间自然也失效了。那么如果你映射的视图函数内部进行反转URL时指定了应用命名空间,那么将会报错,会提示找不到front命名空间,如下:
所以,综上建议,如果你映射的视图函数内部进行反转URL时指定了应用命名空间,最好调用include((pattern_list,app_namespace),namespace=None) 函数,在指定列表或元组 的同时也指定应用命名空间。
标签:额外 使用 ESS list pychar 技术分享 完成后 code cdc
原文地址:http://blog.51cto.com/12731497/2175667