Handling HTTP requests 之URL dispatcher

综述

设计一个web应用的URLs,你需要新建一个Python模块来进行URL设置(URLconf)。这个模块中纯Python代码的并且是一个URL patterns(正则表达式)与Python函数(views)之间的映射匹配。

Django完成一个网络请求的过程。

  • 通常在setting.py文件中使用ROOT_URLCONF设置app的根URL,访问的HttpRequest对象有一个属性是urlconf,对应的值就是ROOT_URLCONF设置的值.
  • Django加载上文中新建的模块,并且寻找相应urlpatterns。urlpatterns是一个包含django.conf.urls.url()实例的列表。
  • Django从上到下搜索每一个URL pattern,在第一个能够匹配的url()实例出停止。
  • 一旦匹配成功Django就会倒入并且调用一个函数(或者是一个class-based view)返回一个视图。获取试图的参数通过以下方式传递

    1. 通过HttpRequest实例传递。
    2. url()实例的正则表达式中传递参数
    3. django.conf.urls.url() 关键字传递参数

  • 如果没有匹配或者匹配过程中出现异常,Django将抛出异常


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

  • 一个http:www.XXX/articles/2005/03/请求将会匹配第三个入口,Django将会调用views.month_archive(request, '2005', '03')函数
  • /articles/2005/3/不会任何匹配,因为第三个入口中需要月份参数是两位数。
  • /articles/2003/将会匹配第一个模式而不是第二个。因为第一个匹配成功了,就不会继续往下走
  • /articles/2003不会有任何的匹配。上文中的每个pattern的结尾都必须要有一个"/"
  • /articles/2003/03/03/ 匹配最后一个模式。并且调用views.article_detail(request, '2003', '03', '03')函数。

    采用 name groups

    采用正则表达式(?Ppattern)patter来匹配,捕获的之作为关键之参数传递给视图表达式。


    from django.conf.urls import url
    from . import views
    urlpatterns = [
    url(r'^articles/2003/$', views.special_case_2003),
    url(r'^articles/(?P[0-9]{4})/$', views.year_archive),
    url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$', views.month_archive),
    url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/(?P[0-9]{2})/$', views.article_detail),
    ]

  • /articles/2005/03/,将会调用 views.month_archive(request, year='2005', month='03')
  • /articles/2003/03/03/ --->views.article_detail(request, year='2003', month='03', day='03')
    同时传递给视图函数的总是strings

    URLconf结果

    URLconf把一个requested URL当成一个普通的Python string搜索。与请求的方法无关(POST、GET)
    https://www.example.com/myapp/ --->匹配 myapp/
    https://www.example.com/myapp/?page=3 ----->匹配 myapp/ 参数可以通过视图函数的request对象实例相关方法回去 request.GET['page']

    指定默认值

    URLconf

    from django.conf.urls import url
    from . import views
    urlpatterns = [
    url(r'^blog/$', views.page),
    url(r'^blog/page(?P[0-9]+)/$', views.page),
    ]

    View (in blog/views.py)

    def page(request, num="1"):
    # Output the appropriate page of blog entries, according to num.
    ...

    在上面的例子中,两个URL模式指向相同的视图-views.page-。但是第一个模式并没有从URL中捕捉到任何东西。如果第一个模式匹配,那么page()函数将使用它的默认参数num“1”。如果第二个模式匹配,page()将使用regex捕获的任何num值

    Including other URLconfs

    include() 函数,可以把urlpatterns放到别的地方去设置


    from django.conf.urls import include, url
    urlpatterns = [
    url(r'^community/', include('django_website.aggregator.urls')),
    url(r'^contact/', include('django_website.contact.urls')),
    ]

    把所有以community开头的请求都交由django_website.aggregator.urls去处理

    也是一种拆分urlpatterns臃肿的办法


    from django.conf.urls import include, url
    from apps.main import views as main_views
    from credit import views as credit_views
    extra_patterns = [
    url(r'^reports/$', credit_views.report),
    url(r'^reports/(?P[0-9]+)/$', credit_views.report),
    url(r'^charge/$', credit_views.charge),
    ]
    urlpatterns = [
    url(r'^$', main_views.homepage),
    url(r'^help/', include('apps.help.urls')),
    url(r'^credit/', include(extra_patterns)),
    ]

    例子中/credit/reports/ 将有credit_views.report()处理。 现在 url(r'^credit/', include(extra_patterns))匹配,再在extra_patterns 寻找进一步的匹配


    include()参数的获取

    In settings/urls/main.py

    from django.conf.urls import include, url
    urlpatterns = [
    url(r'^(?P\w+)/blog/', include('foo.urls.blog')),
    ]

    In foo/urls/blog.py

    from django.conf.urls import url
    from . import views
    urlpatterns = [
    url(r'^$', views.blog.index),
    url(r'^archive/$', views.blog.archive),
    ]

    diyinqianchang/blog/archive/ --->views.blog.archive(request,username='diyinqianchang')

    def archive(request,username=None)

    Reverse resolution of URLs

    在编写web程序时,有时候会需要在网页上嵌入一个连接,用于跳转。也可以用设计好的pattern来产生匹配格式的网址。

  • 在templates中使用此url的标记
  • 在Python代码中reverse()函数 reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
  • get_absolute_url()函数

    name 标记


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

    reverse()


    from django.urls import reverse
    from django.http import HttpResponseRedirect
    def redirect_to_year(request):
    year = 2006
    return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

    URL命名空间

    URL 命名空间允许你反查到唯一的,即使不同的应用使用相同的URL 名称。第三方应用始终使用带命名空间的URL 是一个很好的实践。

    当解析一个带命名空间的URL(例如'polls:index')时,Django 将切分名称为多个部分,然后按下面的步骤查找:

  • 首先,Django 查找匹配的 application namespace, 在下面的例子中为'polls'。这将得到该应用实例的一个列表。
  • 如果当前应用属性被定义,Django将查找并返回那个实例的URL解析器。当前应用属性可在reverse() 函数中通过current_app来指定。
  • 如果没有当前应用。Django 将查找一个默认的应用实例。默认的应用实例是[instance namespace和application namespace 一致的那个实例(在下面例子中,polls的一个叫做'polls' 的实例)
  • 如果没有默认的应用实例,Django 将挑选该应用最后部署的实例,不管实例的名称是什么。
  • 如果提供的命名空间与第1步中的application namespace 不匹配,Django 将尝试直接将此命名空间作为一个 instance namespace查找。

    urls.py
    from django.conf.urls import include, url
    urlpatterns = [
    url(r'^author-polls/', include('polls.urls', namespace='author-polls')),
    url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls')),
    ]

    polls/urls.py
    from django.conf.urls import url
    from . import views
    app_name = 'polls'
    urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P\d+)/$', views.DetailView.as_view(), name='detail'),
    ]

    本例中author-polls和publisher-polls都有相同连写的主页和详细链接,被include() 在polls/urls.py

  • 如果其中一个实例是当前实例 —— 如果我们正在渲染'author-polls' 实例的detail 页面 —— 'polls:index' 将解析成'author-polls' 实例的主页面;例如下面两个都将解析成"/author-polls/"。

    第一和第二
    reverse('polls:index', current_app=self.request.resolver_match.namespace)

    {% url 'polls:index' %}

  • 如果没有当前实例——假如说我们在站点的其他地方渲染页面——'polls:index'将解析到最后注册到polls的实例。因为没有默认的实例(实例命名空间为polls),将用注册的polls的最后一个实例。它将是'publisher-polls',因为它是urlpatterns中最后一个声明的.

  • 'author-polls:index' 将永远解析到 'author-polls' 实例的主页('publisher-polls' 类似) 没有用什么命名空间,用name来标记

  • 你可能感兴趣的:(Handling HTTP requests 之URL dispatcher)