Django路由层

Django的路由系统

Django 1.11版本URLConf官方文档

URL配置(URLconf)就像Django所支撑网站的目录。它的本质是URL与要为该URL调用的视图函数之间的映射表。

路由增加首页的方式

url(r"^$",views.home)

路由增加尾页的方式(当所有的路径都匹配不上时,给 我返回404提示信息)

url(r"",views.error)#放在urls的urlpatterns最后

URLconf配置

基本格式

from django.conf.urls import url

urlpatterns = [
     url(正则表达式, views视图函数,参数,别名),
]

注意:

Django 2.0版本中的路由系统已经替换成下面的写法:

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),
]

参数说明:

正则表达式:一个正则表达式字符

views视图函数:一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串

参数:可选的要传递给视图函数的默认参数(字典形式)

别名:一个可选的name参数

正则表达式详解

基本配置

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),
]

注意事项

  1. urlpatterns中的元素按照书写顺序从上往下逐一匹配正则表达式,一旦匹配成功则不再继续。4
  2. 若要从URL中捕获一个值,只需要在它周围放置一对圆括号(分组匹配)。
  3. 不需要添加一个前导的反斜杠,因为每个URL都有。例如,应该是^articles 而不是 ^/articles。
  4. 每个正则表达式前面的“r”是可选的但是建议加上。

补充说明

#是否开启URL访问地址后面不为/跳转至带有/的路径的配置顶
APPEND_SLASH=True

  Django settings.py配置文件中默认没有 APPEND_SLASH这个参数,但Django默认这个参数为APPEND_SLASH=True。其作用就是自动在网址结尾加“/”。

其效果就是:

我们定义urls.py:

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

urlpatterns = [
        url(r'^blog/$', views.blog),
]

  访问http://www.example.com/blog 时,默认将网址自动转换为 http://www.example/com/blog/

  如果在settings.py中设置了 APPEND_SLASH=False,此时我们再请求http://www.example.com/blog时就会提示找不到页面。

分组命名匹配

  上面的示例使用简单的正则表达式分组匹配(通过圆括号)来捕获URL中的值并以位置参数形式传递给视图。

  在更高级的用法中,可以使用分组命名匹配的正则表达式组来捕获URL中的值并以关键字参数形式传递给视图。

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

下面是以上URLconf使用命名名组的重写:

from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail),
]

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

  例如,针对url /articles/2017/12/相当于按以下方式调用视图函数:

views.month_archive(request, year="2017", month="12")

  在实际应用中,使用分组命名匹配的方式可以让你的URLconf 更加明晰且不容易产生参数顺序问题的错误,但是有些开发人员则认为分组命名组语法太丑陋、繁琐。

  至于究竟应该使用哪一种,你可以根据自己的喜好来决定。

URLconf匹配的位置

URLconf 在请求的URL 上查找,将它当做一个普通的Python 字符串。不包括GET和POST参数以及域名。

例如,http://www.example.com/myapp/ 请求中,URLconf 将查找myapp/。

http://www.example.com/myapp/?page=3 请求中,URLconf 仍将查找myapp/。

URLconf 不检查请求的方法。换句话讲,所有的请求方法 —— 同一个URL的POST、GET、HEAD等等 —— 都将路由到相同的函数

捕捉的参数永远都是字符串

   每个在URLconf中捕获的参数都作为一个普通的Python字符串传递给视图,无论正则表达式使用的是什么匹配方式。例如,下面这行URLconf 中:

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

   传递到视图函数views.year_archive() 中的year 参数永远是一个字符串类型。

视图函数中指定默认值

# urls.py中
from django.conf.urls import url

from . import views

urlpatterns = [
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P<num>[0-9]+)/$', views.page),
]

# views.py中,可以为num指定默认值
def page(request, num="1"):
    pass

  在上面的例子中,两个URL模式指向相同的view - views.page - 但是第一个模式并没有从URL中捕获任何东西。

  如果第一个模式匹配上了,page()函数将使用其默认参数num=“1”,如果第二个模式匹配,page()将使用正则表达式捕获到的num值

include其他的URLconfs

#At any point, your urlpatterns can “include” other URLconf modules. This
#essentially “roots” a set of URLs below other ones.

#For example, here’s an excerpt of the URLconf for the Django website itself.
#It includes a number of other URLconfs:


from django.conf.urls import include, url

urlpatterns = [
   url(r'^admin/', admin.site.urls),
   url(r'^blog/', include('blog.urls')),  # 可以包含其他的URLconfs文件
]

传递额外的参数给视图函数(了解)

  URLconfs 具有一个钩子,让你传递一个Python 字典作为额外的参数传递给视图函数。

  django.conf.urls.url() 函数可以接收一个可选的第三个参数,它是一个字典,表示想要传递给视图函数的额外关键字参数。

例如:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}),
]

  在这个例子中,对于/blog/2005/请求,Django 将调用views.year_archive(request, year='2005', foo='bar')。 这个技术在Syndication 框架中使用,来传递元数据和选项给视图。

无名分组

url(r"^test/([0-9]{4})/",views.test)

  会将加了括号的正则表达式匹配的内容当做位置参数传递给后面的视图函数

又名分组

url(r"^test/(?P<year>d+)",views.twst)

  会将加了括号的正则表达式匹配的内容当做关键字参数传递给后面的视图函数

  关键字就是你尖括号里面的名字(year)

  有名分组和无名不能混合使用!!!

  只要不混着用,有名分组和无名分组支持多个相同类型的参数

命名URL和URL反向解析

  简单来说就是可以给我们的URL匹配规则起个名字,一个URL匹配模式起一个名字。

  这样我们以后就不需要写死URL代码了,只需要通过名字来调用当前的URL。

举个简单的例子:

url(r'^home', views.home, name='home'),  # 给我的url匹配模式起名为 home
url(r'^index/(d*)', views.index, name='index'),  # 给我的url匹配模式起名为index

这样:

  在模板里面可以这样引用(就会直接找到url里面起这个名字的对应处理匹配原则和视图函数):

{% url 'home' %}

在views函数中可以这样引用:

例子:

考虑下面的URLconf:

from django.conf.urls import url

from . import views

urlpatterns = [
    # ...
    url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),
    # ...
]

  根据这里的设计,某一年nnnn对应的归档的URL是/articles/nnnn/。

你可以在模板的代码中使用下面的方法获得它们:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

在Python代码中,这样使用:

from django.urls import reverse
from django.shortcuts import redirect

def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return redirect(reverse('news-year-archive', args=(year,)))

  如果出于某种原因决定按年归档文章发布的URL应该调整一下,那么你将只需要修改URLconf 中的内容。

  在某些场景中,一个视图是通用的,所以在URL 和视图之间存在多对一的关系。对于这些情况,当反查URL 时,只有视图的名字还不够。

注意:

  为了完成上面例子中的URL 反查,你将需要使用命名的URL 模式。URL 的名称使用的字符串可以包含任何你喜欢的字符。不只限制在合法的Python 名称。

  当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL 模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。

  在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment。

命名空间模式

  即使不同的APP使用相同的URL名称,URL的命名空间模式也可以让你唯一反转命名的URL。

举个例子:

project中的urls.py

from django.conf.urls import url, include
 
urlpatterns = [
    url(r'^app01/', include('app01.urls', namespace='app01')),
    url(r'^app02/', include('app02.urls', namespace='app02')),
]

app01中的urls.py

from django.conf.urls import url
from app01 import views
 
app_name = 'app01'
urlpatterns = [
    url(r'^(?P<pk>d+)/$', views.detail, name='detail')
]

app02中的urls.py

from django.conf.urls import url
from app02 import views
 
app_name = 'app02'
urlpatterns = [
    url(r'^(?P<pk>d+)/$', views.detail, name='detail')
]

  现在,我的两个app中 url名称重复了,我反转URL的时候就可以通过命名空间的名称得到我当前的URL。

语法: '命名空间名称:URL名称'

模板中使用:

{% url 'app01:detail' pk=12 pp=99 %}

views中的函数中使用

v = reverse('app01:detail', kwargs={'pk':11})

  这样即使app中URL的命名相同,我也可以反转得到正确的URL了。

前端反向解析

{% url "add" %}#{% url "放urls.py中路由与视图函数的name的值"%}

后端反向解析

from django.shortcuts import render, redirect, HttpResponse, reverse
res=reverse("add")
url(r'^testadd/$', views.testadd,name="add")

反向解析

无名分组的反向解析

前端反向解析

{% url "add" id %}#{% url "放urls.py中路由与视图函数的name的值"%}

后端反向解析

from django.shortcuts import render, redirect, HttpResponse, reverse
res=reverse("add",args=(id,))
url(r'^testadd/(d+)$', views.testadd,name="add")
有名分组的反向解析

前端反向解析

{% url "add" id %}#{% url "放urls.py中路由与视图函数的name的值"%}
{% url "add" id=id %}#{% url "放urls.py中路由与视图函数的name的值"%}

后端反向解析

from django.shortcuts import render, redirect, HttpResponse, reverse
res=reverse("add",args=(id,))
res=reverse("add",kwargs={"id":id})
url(r'^testadd/(?P<id>d+)$', views.testadd,name="add")

Django2.0版的path

django2.0的re_path和1.0的url一样

思考情况如下:

urlpatterns = [  
    re_path('articles/(?P<year>[0-9]{4})/', year_archive),  
    re_path('article/(?P<article_id>[a-zA-Z0-9]+)/detail/', detail_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/edit/', edit_view),  
    re_path('articles/(?P<article_id>[a-zA-Z0-9]+)/delete/', delete_view),  
]

  第一个问题,函数 year_archive 中year参数是字符串类型的,因此需要先转化为整数类型的变量值,当然year=int(year) 不会有诸如如TypeError或者ValueError的异常。那么有没有一种方法,在url中,使得这一转化步骤可以由Django自动完成?

  第二个问题,三个路由中article_id都是同样的正则表达式,但是你需要写三遍,当之后article_id规则改变后,需要同时修改三处代码,那么有没有一种方法,只需修改一处即可?

  在Django2.0中,可以使用 path解决以上的两个问题。

基本实例

from django.urls import path  
from . import views  
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>/', views.article_detail),  
  # path才支持,re_path不支持
  path('order/<int:year>',views.order),
]  

基本规则

  使用尖括号(<>)从url中捕获值。

  捕获值中可以包含一个转换器(converter type),比如"<int:name>"捕获一个整数变量。如果没有转换器,将匹配任何字符串,当然也包括了/字符。

path转换器

 Django默认支持以下5个转换器:

  1. str,匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
  2. int,匹配正整数,包含0
  3. slug,匹配字母、数字以及横杠、下划线组成的字符串
  4. uuid,匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
  5. path,匹配任何非空字符串,包含了路径分隔符(/)

注册自定义转换器

  对于一些复杂或者复用的需要,可以定义自己的转化器。转化器是一个类或接口,它的要求有三点:

  1. regex类属性,字符串类型
  2. to_python(self, value) 方法,value是由类属性 regex所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中
  3. to_url(self, value)方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。

列子:

class FourDigitYearConverter:  
    regex = '[0-9]{4}'  
    def to_python(self, value):  
        return int(value)  
    def to_url(self, value):  
        return '%04d' % value  

使用register_converter将其注册到URL配置中:

from django.urls import register_converter, path  
from . import converters, views  
register_converter(converters.FourDigitYearConverter, 'yyyy')  
urlpatterns = [  
    path('articles/2003/', views.special_case_2003),  
    path('articles/<yyyy:year>/', views.year_archive),  
    ...  
]  

伪静态的概念

  假装自己的路径是一个静态(数据写死的)文件的路径,其实你是经过了视图函数处理,动态渲染页面,提高百度收藏你这个页面力度,当别人搜索你这个页面相关的内容,百度会优先展示你的页面(这样虽然能提高你网页被访问概率,但是还是干不过RMB玩家)

原文地址:https://www.cnblogs.com/ShenJunHui6/p/10712327.html