首先我们来看一下django是如何处理请求的!
Django如何处理一个请求:
- Django 决定要使用的根URLconf 模块。通常,这个值就是ROOT_URLCONF 的设置,但是如果进来的HttpRequest 对象具有一个urlconf 属性(通过中间件request processing 设置),则使用这个值来替换ROOT_URLCONF 设置。
- Django 加载该Python 模块并寻找可用的urlpatterns。它是django.conf.urls.url() 实例的一个Python 列表。
- Django 依次匹配每个URL 模式,在与请求的URL 匹配的第一个模式停下来。
- 一旦其中的一个正则表达式匹配上,Django 将导入并调用给出的视图,它是一个简单的Python 函数(或者一个基于类的视图)。视图将获得如下参数: 一个HttpRequest 实例。
- 如果匹配的正则表达式返回了没有命名的组,那么正则表达式匹配的内容将作为位置参数提供给视图。
- 关键字参数由正则表达式匹配的命名组组成,但是可以被django.conf.urls.url()的可选参数kwargs覆盖。
- 如果没有匹配到正则表达式,或者如果过程中抛出一个异常,Django 将调用一个适当的错误处理视图。
什么是URL?
URL解释:
url 的结构:
schema://host[:port#]/path/.../[?query-string][#anchor]- schema:指定使用的协议(例如:http, https, ftp)
- host:Http服务器的IP地址或者域名
- port:端口号,默认是80端口
- path:访问资源的路径
- query-string:发送给http服务器的数据
- anchor:锚点
下面我们看看url在django中最基础的用法:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.ArticlesYear.as_view()), #普通用法
url(r'^articles/([0-9]{4})/$', views.ArticlesMonth.as_view()), # 单个非命名参数
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.ArticlesActive.as_view()),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.ArticlesAll.as_view()),
]注:
- 若要从URL 中捕获一个值,只需要在它周围放置一对圆括号。
- 不需要添加一个前导的反斜杠,因为每个URL 都有。例如,应该是^articles 而不是 ^/articles。
- 每个正则表达式前面的’r’ 是可选的但是建议加上。它告诉Python 这个字符串是“原始的” —— 字符串中任何字符都不应该转义。
- ” ^” 代表开始匹配,如果只有^符号,则只需要部分匹配成功即可
- 美元符代表结束匹配,添加 代 表 结 束 匹 配 , 添 加符号, 一般就代表完整匹配.
- URL匹配规则一定需要保持唯一
命名组
上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。
在Python 正则表达式中,命名正则表达式组的语法是(?P< name >pattern),其中name 是组的名称,pattern 是要匹配的模式。
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.ArticlesYear.as_view()),
url(r'^articles/(?P<year>[0-9]{4})/$', views.ArticlesMonth.as_view() ),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.ArticlesActive.as_view()),
url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.ArticlesAll.as_view()),
]匹配/分组算法:
- 如果有命名参数,则使用这些命名参数,忽略非命名参数。
- 否则,它将以位置参数传递所有的非命名参数。
- 请求的URL被看做是一个普通的Python 字符串, URLconf在其上查找并匹配。进行匹配时将不包括GET或POST请求方式的参数以及域名。换句话讲,所有的请求方法 —— 即,对同一个URL的无论是POST请求、GET请求、或HEAD请求方法等等 —— 都将路由到相同的函数。
- 每个捕获的参数都作为一个普通的Python 字符串传递给视图,无论正则表达式使用的是什么匹配方式。
指定视图参数的默认值
# URLconf
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^blog/$', views.Page.as_view()),
url(r'^blog/page/(?P<num>[0-9]+)/$', views.Page.as_view()),
]
# View (in blog/views.py)
class Page(View):
def get(self, request, num="1"):
# Output the appropriate page of blog entries, according to num.
...错误处理
- 当Django 找不到一个匹配请求的URL 的正则表达式时,或者当抛出一个异常时,Django 将调用一个错误处理视图。
http常见状态码:
每一个请求,都会返回一个状态
- 200 : 请求正常
- 404:就是找不到页面,或者说匹配不到对应的path路径
- 403:是指服务器拒绝, 一般出现这种情况,是用户被服务器拉进黑名单,或者安全拦截
- 400:你的request异常,一般就是你的请求缺少内容
- 500:服务器异常,这个一般就是代码出现了异常
- 。。。
包含其它的URLconfs
在任何时候,你的urlpatterns 都可以包含其它URLconf 模块。这实际上将一部分URL 放置于其它URL 下面。
from django.conf.urls import include, url
urlpatterns = [
# ... snip ...
url(r'^community/', include('django_website.aggregator.urls')),
url(r'^contact/', include('django_website.contact.urls')),
# ... snip ...
]url匹配时,在项目的urls.py下先进行匹配,然后再匹配对应的include中的URLconf 模块。
URL 的反向解析
在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL。
换句话讲,需要的是一个DRY 机制。除了其它优点,它还允许设计的URL 可以自动更新而不用遍历项目的源代码来搜索并替换过期的URL。
要获取一个URL,最初拥有的信息是负责处理它的视图的标识(例如名字),与查找正确的URL 的其它必要的信息如视图参数的类型(位置参数、关键字参数)和值。
Django 提供了一个解决方案使得URL 映射是URL 设计唯一的储存库。你用你的URLconf填充它,然后可以双向使用它:
- 根据用户/浏览器发起的URL 请求,它调用正确的Django 视图,并从URL 中提取它的参数需要的值。
- 根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL.
在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查
- 在模板中:使用url 模板标签。
- 在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
- 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。
例如:
from django.conf.urls import url
from . import views
urlpatterns = [
#...
url(r'^articles/([0-9]{4})/$', views.Page.as_view() , name='news-year-archive'),
#...
]在模版中使用:
<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.shortcuts import reverse, redirect
from django.views import View
class Page(View)
def get(request):
# ...
year = 2006
# ...
return redirect(reverse('news-year-archive', args=(year,)))URL 模式的命名
- 为了完成上面例子中的URL 反查,你将需要使用命名的URL 模式。URL
的名称使用的字符串可以包含任何你喜欢的字符。并不仅限于合法的Python 名称。 - 当命名你的URL 模式时,请确保使用的名称不会与其它应用中名称冲突。如果你的URL
模式叫做comment,而另外一个应用中也有一个同样的名称,当你在模板中使用这个名称的时候不能保证将插入哪个URL。 - 在URL 名称中加上一个前缀,比如应用的名称,将减少冲突的可能。我们建议使用myapp-comment 而不是comment。
URL 命名空间
URL 命名空间允许你反查到唯一的命名URL 模式,即使不同的应用使用相同的URL 名称。第三方应用始终使用带命名空间的URL 是一个很好的实践。类似地,它还允许你在一个应用有多个实例部署的情况下反查URL。换句话讲,因为一个应用的多个实例共享相同的命名URL,命名空间提供了一种区分这些命名URL 的方法。
一个URL命名空间有两个部分,它们都是字符串:
- 应用命名空间
- 它表示正在部署的应用的名称。一个应用的每个实例具有相同的应用命名空间。例如,可以预见Django 的管理站点的应用命名空间是’admin’。
- 实例命名空间
- 它表示应用的一个特定的实例。实例的命名空间在你的全部项目中应该是唯一的。但是,一个实例的命名空间可以和应用的命名空间相同。它用于表示一个应用的默认实例。
- URL 的命名空间使用’:’ 操作符指定。例如,管理站点应用的主页使用’admin:index’。它表示’admin’的一个命名空间和’index’ 的一个命名URL。
- 命名空间也可以嵌套。命名URL’sports:polls:index’ 将在命名空间’polls’中查找’index’,而poll定义在顶层的命名空间’sports’ 中。
反查带命名空间的URL
当解析一个带命名空间的URL(例如’polls:index’)时,Django 将切分名称为多个部分,然后按下面的步骤查找:
- 首先,Django 查找匹配的应用命名空间(在这个例子中为’polls’)。这将得到该应用实例的一个列表。
- 如果有一个当前应用被定义,Django 将查找并返回那个实例的URL 解析器。当前应用可以通过请求上的一个属性指定。
- 当前应用还可以通过reverse() 函数的一个参数手工设定。
- 如果没有当前应用。Django 将查找一个默认的应用实例。默认的应用实例是实例命名空间 与应用命名空间 一致的那个实例(在这个例子中,polls 的一个叫做’polls’ 的实例)。
- 如果没有默认的应用实例,Django 将挑选该应用最后部署的实例,不管实例的名称是什么。
- 如果提供的命名空间与第1步中的应用命名空间 不匹配,Django 将尝试直接将此命名空间作为一个实例命名空间查找。
- 如果有嵌套的命名空间,将为命名空间的每个部分重复调用这些步骤直至剩下视图的名称还未解析。然后该视图的名称将被解析到找到的这个命名空间中的一个URL。
例如:
假设我们现在有以下两个配置
# urls.py
from django.conf.urls import include, url
urlpatterns = [
url(r'^author-polls/', include('polls.urls', namespace='author-polls', app_name='polls')),
url(r'^publisher-polls/', include('polls.urls', namespace='publisher-polls', app_name='polls')),
]
# polls
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>\d+)/$', views.DetailView.as_view(), name='detail'),
...
]根据以上设置,可以使用下面的查询:
如果其中一个实例是当前实例 —— 如果我们正在渲染’author-polls’ 实例的detail 页面 —— ‘polls:index’将解析成’author-polls’ 实例的主页面;例如下面两个都将解析成”/author-polls/”。
- 在基于类的视图的方法中:
reverse('polls:index',current_app=self.request.resolver_match.namespace)
- 在基于类的视图的方法中:
和在模板中:
{% url 'polls:index' %}