2.8.5Django --5 Django的路由层

Django目录:https://blog.****.net/qq_41106844/article/details/105554082

什么是路由层

URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于客户端发来的某个URL调用哪一段逻辑代码对应执行。

 

简单的路由配置

普通配置

from django.contribimport admin

from django.urlsimport path

 

from app01import views

urlpatterns = [

    path('admin/', admin.site.urls),

    path('index/',views.index),

]

这是普通配置,一个路由代表一个视图,这样适用于首页这些固定的页面。

 

无名分组

假如我们要一个功能是能够通过页面查看每天的日志,我们总不能每天都加一个页面来放日志,我们需要批量处理路由。既然路由是个字符串,那么正则显然是一个适合的处理方式。

 

urls.py

from django.contribimport admin

from django.urlsimport path

from app01import views

urlpatterns = [

    re_path(r'^Journal/2019/$', views.special_case_2019),

    re_path(r'^Journal/([0-9]{4})/$', views.year_archive),

    re_path(r'^Journal/([0-9]{4})/([0-9]{2})/$', views.month_archive),

    re_path(r'^Journal/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail)

]

 

viers.py

def special_case_2019(request):

    return HttpResponse("Using the special_case_2019 function")

 

def year_archive(request,year):

    return HttpResponse("Using the year_archive function  "+str(year))

 

def month_archive(request,year,month):

    return HttpResponse("Using the month_archive function  "+str(year)+" "+str(month))

 

def article_detail(request,year,month,day):

    return HttpResponse("Using the article_detail function  "+str(year)+" "+str(month)+" "+str(day))

这样我们就可以按照符合我们正则表达式的路由分配相应的视图。

例如我们访问:http://127.0.0.1:8080/Journal/2018/05/12/

 
2.8.5Django --5 Django的路由层
 

因为这个url的格式符合路由表第四条,所以使用视图中的article_detail函数。

同时将捕获到的日期也显示出来。

 

注意:

若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。

不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^Journal而不是^/Journal。

每个正则表达式前面的'r' 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义

 

有名分组

上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字参数传递给视图。

在Python 正则表达式中,命名正则表达式组的语法是(?P<name>pattern),其中name是组的名称,pattern是要匹配的模式。

 

urls.py

from django.contribimport admin

from django.urlsimport path

from app01import views

urlpatterns = [

    re_path(r'^Journal/2019/$', views.special_case_2019),

    re_path(r'^Journal/(?P<year>[0-9]{4})/$', views.year_archive),

    re_path(r'^Journal/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),

    re_path(r'^Journal/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]+)/$', views.article_detail)

]

 
2.8.5Django --5 Django的路由层
 

这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。

例如:

Journal/2018/05/12/   这样的路由请求

调用 views.month_archive(request, year='2018', month='05',day='12')

而不是 views.month_archive(request, '2018', '05','12')。 

 

在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 

既你可以在你的视图函数定义中重新安排参数的顺序。  

当然这是以简洁为代价的。

 

views.py

def special_case_2019(request):

    return HttpResponse("Using the special_case_2019 function")

 

def year_archive(request,year):

    return HttpResponse("Using the year_archive function  "+str(year))

 

def month_archive(request,month,year):

    return HttpResponse("Using the month_archive function  "+str(year)+" "+str(month))

 

def article_detail(request,day,year,month):

    return HttpResponse("Using the article_detail function  "+str(year)+" "+str(month)+" "+str(day))

 
2.8.5Django --5 Django的路由层
 

我们将函数的参数顺序颠倒了,然后我们访问:

http://127.0.0.1:8080/Journal/2018/09/

 
2.8.5Django --5 Django的路由层
 

 

路由分发

路由分发就是当一个url请求过来之后先到项目主目录下的urls内,再由这个url做处理分发给其他app内的urls。

这就需要在app内自己建立一个urls.py文件,每一个app都有一个自己的路由表。

one_exa.urls.py

from django.urlsimport re_path,include

urlpatterns = [

    re_path(r'^Journal/', include("app01.urls")),

    re_path(r'^echarts/', include("app02.urls")),

]

 

one_exa.app01.urls.py

from django.urlsimport re_path

from .import views

 

urlpatterns = [

    re_path(r'^$', views.index),

    re_path(r'^2019/$', views.special_case_2019),

    re_path(r'^(?P<year>[0-9]{4})/$', views.year_archive),

    re_path(r'^(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),

    re_path(r'^(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]+)/$', views.article_detail)

]

 

one_exa.app02.urls.py

from django.urlsimport re_path

from .import views

urlpatterns = [

    re_path(r'^tq/$', views.tq),

]

使用include将路由下发到app中的路由表中。

 

我们尝试访问一下:

 
2.8.5Django --5 Django的路由层
 

 

反向解析与命名空间

参考:https://blog.****.net/u014745194/article/details/74010736

首先明确几个概念:

1.在html页面上的内容特别是向用户展示的url地址,比如常见的超链接,图片链接等,最好能动态生成,而不要固定.

2.一个django项目中一般包含了多个django应用(app).

3.一个视图(view)往往对应多个url地址.

随着功能的增加会出现更多的视图,可能之前配置的正则表达式不够准确,于是就要修改正则表达式,但是正则表达式一旦修改了,之前所有对应的超链接都要修改,真是一件麻烦的事情,而且可能还会漏掉一些超链接忘记修改,有办法让链接根据正则表达式动态生成吗? 就是用反向解析的办法。

而在django中实现反向解析URL必备条件就是 url和view能一对一 的匹配,最简单的方式 就是使用name,可以理解为url起了一个名字。

由于name没有作用域,Django在反解URL时,会在项目全局顺序搜索,当查找到第一个name指定URL时,立即返回

我们在开发项目时,会经常使用name属性反解出URL,当不小心在不同的app的urls中定义相同的name时,可能会导致URL反解错误,为了避免这种事情发生,引入了命名空间。

 

应用范围:1模板中的超链接;2视图中的重定向

使用方法:

定义url时,需要为include定义namespace属性,为url定义name属性

使用时,在模板中使用url标签,在视图中使用reverse函数,根据正则表达式动态生成地址,减轻后期维护成本。

 

在模板使用url标签的步骤:

在总路由表:

re_path(r'^fxjx/', include("app03.urls",namespace='booktest')),

在app路由表

app_name ='app03'

urlpatterns = [

    re_path(r'^fan2/$', views.fan2,name='fan2'),

]

在模板超链接

<a href="{%url 'booktest:fan2'%}">

 

在视图使用重定向的步骤:

在总路由表:

re_path(r'^fxjx/', include("app03.urls",namespace='booktest')),

在app路由表

app_name ='app03'

urlpatterns = [

    re_path(r'^fan2/$', views.fan2,name='fan2'),

]

在视图重定向

from django.core.urlresolvers import reverse

 return redirect(reverse('booktest:fan2'))

 

做一个实例

 
2.8.5Django --5 Django的路由层
新建一个app

 

我们先做模板中的超链接

修改one_exa.urls.py

from django.urls import re_path,include

urlpatterns = [

    re_path(r'^Journal/', include("app01.urls")),

    re_path(r'^echarts/', include("app02.urls")),

    re_path(r'^fxjx/', include("app03.urls",namespace='booktest')),

]

 
2.8.5Django --5 Django的路由层
 

one_exa.app03.urls.py

from django.urls import re_path

from . import views

 

app_name ='app03'

urlpatterns = [

    re_path(r'^fan2/$', views.fan2,name='fan2'),

]

 
2.8.5Django --5 Django的路由层
 

 

one_exa.app03.views.py

from django.shortcutsimport render

# Create your views here.

def fan2(request):

    return render(request,"fan2.html")

 
2.8.5Django --5 Django的路由层
 

 

one_exa.templates.fan2.html

<!DOCTYPE html>

<html lang="en">

    <meta charset="UTF-8">

    <title>Title

        普通链接:<a href="/fan2/">普通fan2

        <hr>

        反向解析:<a href="{%url 'booktest:fan2'%}">反向解析fan2

</html>

 
2.8.5Django --5 Django的路由层
 

 

之后查看页面:

 
2.8.5Django --5 Django的路由层
 

他们的结果是相同的。

 

之后我们修改一下路由:

 
2.8.5Django --5 Django的路由层
 
 
2.8.5Django --5 Django的路由层
 

页面也发生了改变。

这样一来通过命名空间,无论在templates文件中有多庞大的url地址映射,只要使用url软编码,在更改路由系统的时候,都能自动生成。而如果使用硬链接硬编码 ,就只能在views.py和静态文件中逐个修改url地址,不仅耗费时间,更容易产生错误。

 

之后做视图中的重定向

这里简单举一个例子,具体可查看下一章视图层。

修改one_exa.urls.py

from django.urlsimport re_path,include

urlpatterns = [

    re_path(r'^Journal/', include("app01.urls")),

    re_path(r'^echarts/', include("app02.urls",namespace='visible')),

    re_path(r'^fxjx/', include("app03.urls",namespace='booktest'))

]

 
2.8.5Django --5 Django的路由层
 

 

one_exa.app02.urls.py

from django.urlsimport re_path

from .import views

app_name='app02'

urlpatterns = [

    re_path(r'^tq/$', views.tq,name='zx'),

]

 
2.8.5Django --5 Django的路由层
 

 

one_exa.app03.views.py

from django.shortcuts import redirect,reverse

# Create your views here.

def fan2(requests):

    return redirect(reverse('visible:zx'))

 
2.8.5Django --5 Django的路由层
 

 

之后我们访问http://127.0.0.1:8080/fxjx/fan2/

就会直接跳转到http://127.0.0.1:8080/echarts/tq/

 
2.8.5Django --5 Django的路由层
 
 
2.8.5Django --5 Django的路由层
302重定向

 

视图中的重定向传参

 

 
2.8.5Django --5 Django的路由层
 
 
2.8.5Django --5 Django的路由层
 
 
2.8.5Django --5 Django的路由层
 

这样只要访问符合语法的网页,就自动跳转到http://127.0.0.1:8080/fxjx/fan110_26/