码迷,mamicode.com
首页 > 编程语言 > 详细

谈谈Python之Django搭建企业级官网(第三篇下部)

时间:2018-09-16 00:32:51      阅读:305      评论:0      收藏:0      [点我收藏+]

标签:额外   使用   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怎么修改也影响不到其他地方。

Path函数

在学习URL命名之前,先详细学习下Path函数的使用。
path 函数的定义为:

path(route,view,name=None,kwargs=None)  。

以下对这几个参数进行讲解。

  1. route 参数: url 的匹配规则。这个参数中可以指定 url 中需要传递的参数,上一篇文章已讲解,这个参数不再赘述。请移步到谈谈Python之Django搭建企业级官网(第三篇上部)
  2. view 参数:可以为一个视图函数或者是 类视图.as_view() 或者是 django.urls.include() 函数的返回值。
  3. name 参数:这个参数是给这个 url 取个名字的,这在项目比较大, url 比较多的时候用处很大。这个参数就是用于URL命名。
  4. kwargs 参数:有时候想给视图函数传递一些额外的参数,就可以通过 kwargs 参数进行传递。这个参数接收一个字典。会将foo=bar作为关键字实参传入视图函数,所以视图函数要有形参来接收实参。
    比如以下的 url 规则:
    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参数来接收这个额外的参数。

URL命名

学习完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不会再懵逼了。

include函数

在上一篇文章我们知道,在项目不断庞大以后,经常不会把所有的 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) 函数,在指定列表或元组 的同时也指定应用命名空间。

后面的内容明天补充.....

谈谈Python之Django搭建企业级官网(第三篇下部)

标签:额外   使用   ESS   list   pychar   技术分享   完成后   code   cdc   

原文地址:http://blog.51cto.com/12731497/2175667

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!