Django之路由系统

Django的路由系统就是URL配置(URLconf),让Django知道哪一个链接调用哪一个View函数,简单的来说就是URL模式(正则表达式)到Pyhon函数(View)之间的简单的映射关系。

django

0x00 URLconf的基本配置

URLconf在项目的urls.py中,配置的基本格式已经写好了,可以照着已有模板进行山寨,下面是Django1.x的基本配置。

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/([0-9]{4})/$', views.year_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
    url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]

而在Django2.x的URLconf略有不同,关键字也变为了path,不同总体来说都是大同小异。

from django.urls import path

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

总体来说,配置文件可以分为4个部分。

  • 正则表达式:用来配置URL的
  • View视图函数:用来映射需要调用的函数
  • 参数:可以给映射的函数进行传参(字典的方式传参)
  • 别名及命名空间:name、namespace

0x01 分组及分组命名匹配

a_分组

在上面的示例中(Django1.x),除了写了固定的链接外,还有的用( )进行了分组,空号的作用则是讲匹配到的部分作为参数传递给了调用的View的函数,作为参数。

在urls.py配置好app01项目的路由。([0-9]{2,4})匹配到的字符串将会作为参数传递给视图中的test函数。

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/([0-9]{2,4})/', views.test),
]

app01项目的函数如下。

from django.shortcuts import render,HttpResponse

# Create your views here.
def test(request,myArg):
    print(myArg)
    return HttpResponse(myArg)

当输入类似127.0.0.1/test/02/时候,则在终端显示了02,而浏览器页面显示出了02。

也就是说其默认的是按位置进行传参,当有多个参数时,则按照顺序进行传参。

b_分组命名匹配

分组命名匹配则于分组匹配有一点区别,其传参的方式为关键字传参。

# urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/(?P<num>[0-9]{2,4})/', views.test),
]
# app01/views.py

from django.shortcuts import render,HttpResponse

# Create your views here.
def test(request,num):
    print(num)
    return HttpResponse(num)

当输入链接后,匹配到的项目则通过关键字的方式传递给了views中的相应函数,并且作为以分组命名的名字,传递给了函数中名字相同的形参。也就是说其传递的参数为num=02。

一种特殊的用法

在博客中的第一页默认显示域名,而第二页,则显示”域名/2/”,这样,我们可以在View的函数中,传一个位置默认值。注意url配置中为{0,4}。

url(r'^test/(?P<num>[0-9]{0,4})/', views.test),
# app01/views.py

from django.shortcuts import render,HttpResponse

# Create your views here.
def test(request,num=1):
    print(num)
    return HttpResponse(num)

这样就可以实现首页不显示1的效果了。

0x02 include的用法

当app较多的时候,一堆的配置都集中在了urls.py中,那么会很乱,可以通过include进行分流导入不同的app中的urls.py在进行映射。在使用include之前,需要导入include。

# urls.py

from django.conf.urls import url,include
from django.contrib import admin
from app01 import urls as app01urls

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/', include(app01urls)),
]
# app01/urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^test/(?P<num>[0-9]{0,4})/', views.test),
]

Views,部分同上。这样你访问 127.0.0.1/app01/test/02/ ,则可以访问到View中的函数。

0x03 URL命名于URL反向解析

在URLconf中通常都是将URL或者匹配规则写死,一旦要重命名URL则无法映射到了之前相应的函数上,那么可以通过URL命名反向解析的方式来进行URL映射,依旧可以映射到之前的函数上。

做了一个卖车和卖房子的网页,其之前有一个好友链接,指向了对方的网站。映射关系依旧是主程序使用了inclue,在app01里进行操作演示。

# home.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Home homepage</title>
</head>
<body>
<p>这是一个卖房的网站</p>
<a href="/app01/car/">买车网站</a>
</body>
</html>

卖车的网页代码和这个一致。

# app01/urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views


urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^home/', views.home),
    url(r'^car/', views.car),
]

一旦我们将配置的文件中^home/’或者^car/’,名字改变后,则无法映射到对方的网站上了。虽然一般情况下,是不会去修改链接的,但是极端情况下,如果修改链接,我们可以通过使用name的方式来进行命名,之后及时改了链接也可以映射到相应的页面上。

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^home/', views.home,name='homeweb'),
    url(r'^car/', views.car,name='carweb'),
]

而页面文件HTML也需要进行相应的修改。

<a href={% url 'carweb' %}>买房网站</a>

这样进行修改后,链接即使修改后也依旧可以通过好友链接访问到,其自动已经在页面上变为了新的网址。

而在View中,则需要进行反转reverse。如果原来是redirect(‘/app01/car/’),则可以通过下面的方法来修改。

def home(request):
    reverse_url = reverse('carweb')
    print(reverse_url)
    return redirect(reverse_url)

总结:反向解析有2种使用方法,在模板语言种使用和在View种使用。具体操作见上面2段代码。

# 在模板语言中
{% url "别名" var %}
# View中
# 位置传参
reverse("别名", args=(2018, "nb"))
# 关键字传参
reverse("别名" kwargs={"year": 2018, "title": "nb"})

命名空间模式

当使用URL反向解析的时候,当app01和app01中都有name = ‘test’,的URL路由时,如何能解析到正确的View中呢?则需要使用namespace命名空间的模式。对于上述情况在程序的urls.py中设置namespace。

# urls.py

from django.conf.urls import url,include
from django.contrib import admin
from app01 import urls as app01urls
from app01 import urls as app02urls

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^app01/', include(app01urls,namespace='app01')),
    url(r'^app02/', include(app02urls,namespace='app02')),
]

接下来进行带有namespace的url进行反向解析。解析方法与之前的基本一致,只是使用了”命名空间:别名”的形式进行解析。

# 在模板语言中
{% url "app01:test" var %}
# 在View中
reverse("app01:test")

这样在name相同的情况下,我们也可以解析到正确的URL上。

发表评论