Django 如何处理请求

Django 通过将传入的 URL 路径路由到视图函数来处理请求。view 函数负责将响应返回给发出请求的客户端。不同的 URL 通常由不同的视图函数处理。要将请求路由到特定的视图函数,Django 会查看你的 URL 配置(或简称 URLconf)。默认项目模板定义 <myproject>/urls.py 中的 URLconf。

你的 URLconf 应该是一个 python 模块,它定义了一个名为 urlpatterns 的属性,该属性是 django.conf.urls.url() 实例的列表。每个 url() 实例必须至少定义一个正则表达式 (一个正则表达式)来匹配 URL,以及一个目标,它是一个视图函数或一个不同的 URLconf。如果 URL 模式以视图函数为目标,则最好为其命名,以便以后轻松引用该模式。

我们来看一个基本的例子:

# In <myproject>/urls.py

from django.conf.urls import url

from myapp.views import home, about, blog_detail

urlpatterns = [
    url(r'^$', home, name='home'),
    url(r'^about/$', about, name='about'),
    url(r'^blog/(?P<id>\d+)/$', blog_detail, name='blog-detail'),
]

此 URLconf 定义了三种 URL 模式,所有这些模式都以视图为目标:homeaboutblog-detail

  • url(r'^$', home, name='home'),

正则表达式包含一个起始锚点’^’,紧接着是一个结束锚’$’。此模式将匹配 URL 路径为空字符串的请求,并将它们路由到 myapp.views 中定义的 home 视图。

  • url(r'^about/$', about, name='about'),

此正则表达式包含一个起始锚点,后跟文字字符串 about/和结束锚点。这将匹配 URL /about/并将其路由到 about 视图。由于每个非空 URL 都以/开头,因此 Django 可以方便地为你剪切第一个斜杠。

  • url(r'^blog/(?P<id>\d+)/$', blog_detail, name='blog-detail'),

这个正则表达式有点复杂。它定义了起始锚点和文字字符串 blog/,就像前面的模式一样。下一部分 (?P<id>\d+) 被称为捕获组。捕获组(如其名称所示)捕获字符串的一部分,Django 将捕获的字符串作为参数传递给视图函数。

捕获组的语法是 (?P<name>pattern)name 定义组的名称,这也是 Django 用于将参数传递给视图的名称。该模式定义了组匹配的字符。

在这种情况下,名称为 id,因此函数 blog_detail 必须接受名为 id 的参数。模式是\d+\d 表示该模式仅匹配数字字符。+表示模式必须匹配一个或多个字符。

一些常见的模式:

blog-detail 模式中的捕获组后面是文字/和结束锚。

有效的网址包括:

  • /blog/1/ # passes id='1'
  • /blog/42/ # passes id='42'

例如,无效的网址是:

  • /blog/a/ # 'a' does not match '\d'
  • /blog// # no characters in the capturing group does not match '+'

Django 按照在 urlpatterns 中定义的相同顺序处理每个 URL 模式。如果多个模式可以匹配相同的 URL,这一点很重要。例如:

urlpatterns = [
    url(r'blog/(?P<slug>[\w-]+)/$', blog_detail, name='blog-detail'),
    url(r'blog/overview/$', blog_overview, name='blog-overview'),
]

在上面的 URLconf 中,第二个模式是不可访问的。该模式将匹配 URL /blog/overview/,但不是调用 blog_overview 视图,URL 将首先匹配 blog-detail 模式并使用参数 slug='overview'调用 blog_detail 视图。

为了确保 URL /blog/overview/被路由到 blog_overview 视图,模式应该放在 blog-detail 模式之上:

urlpatterns = [
    url(r'blog/overview/$', blog_overview, name='blog-overview'),
    url(r'blog/(?P<slug>[\w-]+)/$', blog_detail, name='blog-detail'),
]