Django商城URL设置


URL

路由称为URL(Uniform Resource Locator,统一资源定位符),也可以称为URLconf,是对可以从互联网上得到的资源位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的路由,用于指出网站文件的路径位置。简单地说,路由可视为我们常说的网址,每个网址代表不同的网页。

设置路由分发规则

一个完整的路由包含:路由地址、视图函数(或者视图类)、路由变量和路由命名。其中基本的信息必须有:路由地址和视图函数(或者视图类),路由地址即我们常说的网址;

视图函数(或者视图类)即项目应用(App)的views.py文件所定义的函数或类;路由变量和路由命名是路由的变量和命名设置,使路由具有动态变化和命名引用功能。(动态变化是指一个路由地址按照某个规律演变多种不同的路由地址;

命名引用是指在视图、模型等其他项目文件使用路由命名生成相应的路由地址)在默认情况下,设置路由地址是在项目同名的文件夹的urls.py文件里实现,这也是由配置文件settings.py的ROOT_URLCONF决定,以项目babys为例,配置属性ROOT_URLCONF指向babys文件夹的urls.py,如图3-1所示。

一个项目中可能设有多个项目应用(App),而babys文件夹的urls.py是定义项目所有路由地址的总入口,如果项目中所有路由地址都在babys文件夹的urls.py中定义,当项目功能规模越来越大的时候,babys文件夹的urls.py定义的路由地址就会越来越多,从而造成难以管理的问题。为了更好区分各个项目应用(App)的路由地址,我们在babys文件夹的urls.py中分别为每个项目应用(App)定义一条路由入口。首先在每个项目应用(App)的文件夹里创建urls.py文件,以项目babys的项目应用index为例,其目录结构如图3-2所示。

除了项目应用index之外,我们还要在项目应用shopper和commodity分别创建新的urls.py文件。然后在PyCharm里打开babys文件夹的urls.py文件,将项目应用index、shopper和commodity新建的urls.py添加到babys文件夹的urls.py,添加方法由Django内置函数path和include实现,详细代码如下:

from django.contrib import admin:导入内置Admin功能模块。

from django.urls import path,include:导入Django的路由函数模块。

urlpatterns:代表整个项目的路由集合,以列表格式表示,每个元素代表一条路由信息。

path('admin/', admin.site.urls):设定Admin管理系统的路由信息。

'admin/'代表127.0.0.1:8000/admin的路由地址,admin后面的斜杠是路径分隔符,其作用等同于计算机中文件目录的斜杠符号;

admin.site.urls指向内置Admin功能所自定义的路由信息,可以在Python目录Lib\site-packages\django\contrib\admin\sites.py中找到具体的定义过程。

path('', include(('index.urls', 'index'), namespace='index')):路由地址为“/”,即127.0.0.1:8000,通常是网站的首页;路由函数include是将该路由地址分发给项目应用index的urls.py处理。

path('commodity', include(('commodity.urls', 'commodity'), namespace='commodity')):路由地址为“/commodity”,即127.0.0.1:8000/commodity,这是商品详细和商品列表页面;路由函数include是将该路由地址分发给项目应用commodity的urls.py处理。

path('shopper', include(('shopper.urls', 'shopper'), namespace='shopper')):路由地址为“/shopper”,即127.0.0.1:8000/shopper,这是购物车、个人中心、用户注册等页面;路由函数include是将该路由地址分发给项目应用shopper的urls.py处理。

re_path('media/(?P.*)', serve, {'document_root':settings.MEDIA_ROOT}, name='media'):路由地址为“/media/xxx”,即127.0.0.1:8000/media/xxx,这是媒体资源定义的路由地址,路由函数re_path表示允许在路由地址里面设置正则表达式。

从babys文件夹的urls.py定义的路由信息得知,每个项目应用(App)的路由地址交给项目应用的urls.py自行管理,这是路由的分发规则,使路由按照一定的规则进行分类管理。整个路由设计模式的工作原理说明如下:

(1)当运行babys项目时,Django从babys文件夹的urls.py找到各个项目应用(App)的urls.py,然后读取每个项目应用(App)的urls.py定义的路由信息,从而生成完整的路由列表。

(2)用户在浏览器上访问某个路由地址时,Django就会收到该用户的请求信息。

(3)Django从当前请求信息中获取路由地址,并在路由列表里匹配相应的路由信息,再执行路由信息所指向的视图函数(或视图类),从而完成整个请求响应过程。

路由分发详解

我们设置项目路由分发功能的时候,除了使用内置函数path和include之外,还在路由中设置了参数namespace,该参数是可选参数,是Django设置路由的命名空间。

路由函数include设有参数arg和namespace,参数arg指向项目应用App的urls.py文件,其数据格式以元组或字符串表示;可选参数namespace是路由的命名空间。

若要对路由设置参数namespace,则参数arg必须以元组格式表示,并且元组的长度必须为2。以路由path('',include(('index.urls', 'index'), namespace='index'))为例,参数arg为('index.urls', 'index'),参数的每个元素说明如下:

第一个元素为项目应用的urls.py文件,比如('index.urls','index')的“index.urls”,这是代表项目应用index的urls.py文件。

第二个元素可以自行命名,但不能为空,一般情况下是以项目应用的名称进行命名,如('index.urls','index')的“index”是以项目应用index进行命名的。

Django的命名空间namespace可以为我们快速定位某个项目应用的urls.py,再结合路由命名name就能快速地从项目应用的urls.py找到某条路由的具体信息,这样就能有效管理整个项目的路由列表。有关路由函数include的定义过程,可以在Python安装目录下找到源码(Lib\site-packages\django\urls\conf.py)进行解读。

设置商城的路由地址

我们已在babys文件夹的urls.py分别为项目应用index、shopper和commodity设置路由分发功能,本节将会在项目应用index、shopper和commodity的urls.py定义网站首页、商品列表页、商品详细页、购物车页面、个人中心页面和用户登录注册页面的路由地址。首先打开项目应用index的urls.py,在该文件中定义网站首页的路由地址,定义方法如下:

上述代码中,我们只在项目应用index的urls.py定义了路由地址index,路由地址由Django内置函数path完成定义过程,函数path设置了3个参数,每个参数的说明如下:

(1)第一个参数为空字符串,这是设置具体的路由地址,由于babys文件夹的urls.py的路由分发为path('',include(('index.urls', 'index'), namespace='index')),即代表网址127.0.0.1:8000,而index的urls.py定义的路由地址index设为空字符串,那么路由地址index的网址为127.0.0.1:8000。

(2)第二个参数为indexView,这是指向项目应用index的views.py的某个视图函数或视图类,当用户在浏览器访问127.0.0.1:8000的时候,Django将接收到一个HTTP请求,从该请求中获取路由地址并与自身的路由列表进行匹配,如果路由地址匹配成功,Django将HTTP请求交给路由地址指向的某个视图函数或视图类进行业务处理。

下一步打开项目应用commodity的urls.py,在该文件中定义商品列表页和商品详细页的路由地址,详细的定义过程如下:

上述代码分别定义了商品列表页的路由地址commodity和商品详细页的路由地址detail,路由地址的定义说明如下:

(1)项目应用commodity的urls.py路由空间是path('commodity', include(('commodity.urls','commodity'),namespace='commodity')),因此路由commodity为127.0.0.1:8000/commodity.html,路由detail为127.0.0.1:8000/commodity/detail/id.html。

(2)路由detail设置了路由变量id,该变量以整数型表示,它可以代表1、2、3……等整数,变量id对应商品信息表的主键id,通过改变变量id的数值可以查看不同商品的详细介绍。

(3)路由地址的末端设置了“.html”,这是一种伪静态URL技术,可将网址设置为静态网址,用于SEO搜索引擎的爬取,如百度、谷歌等。此外,在末端设置“.html”是为变量id设置终止符,假如末端没有设置“.html”,并且路由变量为字符串类型,在浏览器上输入无限长的字符串,路由也能正常访问。

(4)路由commodity和detail的业务逻辑处理分别指向项目应用commodity的views.py定义的视图函数commodityView和detailView。

最后打开项目应用shopper的urls.py,在该文件中定义个人中心页、购物车信息页、用户登录注册页和用户注销的路由地址,详细代码如下:

上述代码定义了4条路由地址,每个路由所对应的功能说明如下:

(1)路由shopper代表个人中心页,它的路由空间是path('shopper', include(('shopper.urls','shopper'),namespace='shopper')),因此路由地址为127.0.0.1:8000/shopper.html,个人中心页的业务逻辑由项目应用shopper的views.py定义的视图函数shopperView实现。

(2)路由login代表用户登录注册页,路由地址为127.0.0.1:8000/shopper/login.html,它的业务逻辑由项目应用shopper的views.py定义的视图函数loginView实现。

(3)路由logout实现个人中心的用户注销功能,路由地址为127.0.0.1:8000/shopper/logout.html,它的业务逻辑由项目应用shopper的views.py定义的视图函数logoutView实现。

(4)路由shopcart代表购物车信息页,路由地址为127.0.0.1:8000/shopper/shopcart.html,它的业务逻辑由项目应用shopper的views.py定义的视图函数shopcartView实现。

路由的定义规则

我们已在项目应用index、shopper和commodity的urls.py中定义了网站首页、商品列表页、商品详细页、购物车页面、个人中心页面、用户注销和用户登录注册页面的路由地址。综合分析得知,路由地址的定义规则如下:

(1)每个urls.py文件的路由地址必须在列表urlpatterns里定义,换句话说,每个urls.py必须设有一个列表urlpatterns,该列表是用于定义路由信息。

(2)每条路由是由函数path定义,函数path设置了3个参数:第一个参数是设置具体的路由地址;第二个参数是指向项目应用的views.py的某个视图函数或视图类,负责处理路由的业务逻辑;第三个参数为name='index',这是函数path的可选参数,该参数是命名路由地址。

(3)如果函数path第二个参数使用内置函数include,该路由是实现路由分发功能。也就是说,如果函数path的第二个参数是函数include,该路由为路由分发;如果函数path的第二个参数是项目应用的views.py的视图类或视图函数,该路由为网站的路由地址。

函数path是Django 2.0以上版本定义的内置函数,如果开发环境是Django 1.X版本,那么路由定义应使用函数url。从参数的角度分析,函数path和函数url的参数设置是相同的,只不过函数url定义的路由地址需设置路由符号^和$。^代表当前路由地址的相对路径;$代表当前路由地址的终止符。我们以项目应用commodity的urls.py为例,对路由commodity和detail使用的函数url进行定义,定义过程如下所示。

从上述代码看到,函数url要为每个路由地址设置路由符号^$,而且路由变量id应使用正则表达式表示(如(?P<id>\d+)。综上所述,Django 1的路由规则是使用Django的url函数实现路由定义,并且路由地址设有路由符号^和$,读者需要区分路由符号^和$的作用与使用规则,在某种程度上,它比Django 2版本复杂并且代码可读性差,因此Django 1的路由规则应该会在Django以后的新版本里逐渐淘汰。

路由变量与正则表达式

路由detail在路由地址里设置了路由变量id,通过动态改变路由变量id的数值就能生成相应的商品详细介绍页面,Django的路由变量分为字符类型、整型、slug和uuid,最为常用的是字符类型和整型。

各个类型说明如下:

字符类型:匹配任何非空字符串,但不含斜杠。如果没有指定类型,就默认使用该类型。

整型:匹配0和正整数。slug:可理解为注释、后缀或附属等概念,常作为路由的解释性字符。可匹配任何ASCII字符以及连接符和下画线,能使路由更加清晰易懂。比如网页的标题是“13岁的孩子”,其路由地址可以设置为“13-sui-de-hai-zi”。

uuid:匹配一个uuid格式的对象。为了防止冲突,规定必须使用“-”并且所有字母必须小写,例如075194d3-6885-417e-a8a8-6c931e272f00。

在路由中,如果使用函数path定义路由,那么路由变量则使用变量符号“<>”定义。在括号里面以冒号划分为两部分,冒号前面代表的是变量的数据类型,冒号后面代表的是变量名,变量名可自行命名,如果没有设置变量的数据类型,就默认为字符类型。比如路由变量<year><int:month>`<slug:day>,变量说明如下:

<year>:变量名为year,数据格式为字符类型,与的含义一样。

<int:month>:变量名为month,数据格式为整型。

<slug:day>:变量名为day,数据格式为slug。

除了在路由地址设置变量外,Django还支持在路由地址外设置变量(路由的可选变量),比如在路由detail的路由中添加可选变量user,如下所示:

从上述代码可以看出,可选变量user的设置规则如下:

可选变量只能以字典的形式表示。

设置的可选变量只能在视图函数中读取和使用。

字典的一个键值对代表一个可选变量,键值对的键代表变量名,键值对的值代表变量值。

变量值没有数据格式限制,可以为某个实例对象、字符串或列表(元组)等。

可选变量必须在视图函数(视图类)和参数name之间。

不管我们在路由地址中添加路由变量或者添加可选变量,只要路由信息里设置了变量,都必须在对应的视图函数里设置对应的函数参数,并且函数参数必须与路由信息的变量名一一对应。

虽然路由变量可以使用字符类型、整型、slug和uuid表示,但某些路由变量会因为业务需求或实际情况而设置一定的范围值,比如变量,该变量代表年份,年份都是由4位数字组成,而整型的数值可以长达10位。

为了进一步规范路由变量的数据格式,可以使用正则表达式限制路由变量的取值范围,示例如下:

路由的正则表达式是由路由函数re_path定义的,其作用是对路由变量进行截取与判断,正则表达式是以小括号为单位的,每个小括号的前后可以使用斜杠或者其他字符将其分隔与结束。

以上述代码为例,分别将变量year、month和day以斜杠隔开,每个变量以一个小括号为单位,在小括号内,可分为3部分,以(?P<year>[0-9]{4})为例。

?P是固定格式,字母P必须为大写。

<year>为变量名。

[0-9]{4}是正则表达式的匹配模式,代表变量的长度为4,只允许取0~9的值。

本章小结

路由称为URL(Uniform Resource Locator,统一资源定位符),也可以称为URLconf,是对可以从互联网上得到的资源位置和访问方法的一种简洁的表示,是互联网上标准资源的地址。

互联网上的每个文件都有一个唯一的路由,用于指出网站文件的路径位置。简单地说,路由可视为我们常说的网址,每个网址代表不同的网页。

一个完整的路由包含:路由地址、视图函数(或者视图类)、路由变量和路由命名。其中基本的信息必须有:

路由地址和视图函数(或者视图类),路由地址即我们常说的网址;

视图函数(或者视图类)即项目应用(App)的views.py文件所定义的函数或类;

路由变量和路由命名是路由的变量和命名设置,使路由具有动态变化和命名引用功能。(动态变化是指一个路由地址按照某个规律演变多种不同的路由地址;命名引用是指在视图、模型等其他项目文件使用路由命名生成相应的路由地址)

路由函数include的作用是将当前路由分配到某个项目应用的urls.py文件,而项目应用的urls.py文件可以设置多条路由,这种情况类似计算机上的文件夹A,并且该文件夹下包含多个子文件夹,而Django的命名空间namespace相当于对文件夹A进行命名。

假设项目路由设计为:在babys文件夹的urls.py定义3条路由,每条路由都使用路由函数include,并分别命名为A、B、C,每条路由对应某个项目应用的urls.py文件,并且每个项目应用的urls.py文件里定义若干条路由。

根据上述的路由设计模式,将babys文件夹的urls.py视为计算机上的D盘,在D盘下有3个文件夹,分别命名为A、B、C,每个项目应用的urls.py所定义的若干条路由可视为这3个文件夹里面的文件。在这种情况下,Django的命名空间namespace等同于文件夹A、B、C的文件名。路由函数path是定义项目的路由信息,定义规则如下:

(1)每个urls.py文件的路由地址必须在列表urlpatterns里定义,换句话说,每个urls.py必须设有一个列表urlpatterns,该列表是用于定义路由信息。

(2)每条路由是由函数path定义,函数path设置了3个参数:第一个参数是设置具体的路由地址;第二个参数是指向项目应用的views.py的某个视图函数或视图类,负责处理路由的业务逻辑;第三个参数为name='index',这是函数path的可选参数,该参数是命名路由地址。

(3)如果函数path第二个参数使用内置函数include,该路由是实现路由分发功能。也就是说,如果函数path的第二个参数是函数include,该路由为路由分发;如果函数path的第二个参数是项目应用的views.py的视图类或视图函数,该路由为网站的路由地址

Django的路由变量分为字符类型、整型、slug和uuid,最为常用的是字符类型和整型。各个类型说明如下:

字符类型:匹配任何非空字符串,但不含斜杠。如果没有指定类型,就默认使用该类型。

整型:匹配0和正整数。slug:可理解为注释、后缀或附属等概念,常作为路由的解释性字符。可匹配任何ASCII字符以及连接符和下画线,能使路由更加清晰易懂。比如网页的标题是“13岁的孩子”,其路由地址可以设置为“13-sui-de-hai-zi”。

uuid:匹配一个uuid格式的对象。为了防止冲突,规定必须使用“-”并且所有字母必须小写,例如075194d3-6885-417e-a8a8-6c931e272f00。

路由的正则表达式是由路由函数re_path定义的,其作用是对路由变量进行截取与判断,正则表达式是以小括号为单位的,每个小括号的前后可以使用斜杠或者其他字符将其分隔与结束。

以上述代码为例,分别将变量year、month和day以斜杠隔开,每个变量以一个小括号为单位,在小括号内,可分为3部分,以(?P<year>[0-9]{4})为例:?P是固定格式,字母P必须为大写。<year>为变量名。[0-9]{4}是正则表达式的匹配模式,代表变量的长度为4,只允许取0~9的值。