Django 如何处理一个请求
1.用户发送一个请求。
2.到达Django系统,系统根据settings文件里面的ROOT_URLCONF变量找到要使用的根url模块。
3.找到根url模块以后,依次进行匹配url。
4.匹配上一个url后,如果没有下一级的url匹配则调用视图函数,处理请求,若有下一级url匹配,则进入下一级继续匹配,直到找到最终获得一个视图函数进行处理(视图函数的第一个参数为HttpRequest对象)。
5.经过视图函数处理过后给用户返回一个HttpResponse对象。
什么是视图
一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片… 是任何东西都可以。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你的Python目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,约定是将视图放置在放置在项目或应用程序目录中的名为views.py的文件中。
简单的URLconf例子:
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),
]
命名组:
命名正则表达式组的语法是(?Ppattern),其中name 是组的名称,pattern 是要匹配的模式。
URLconf 在什么上查找
请求的URL被看做是一个普通的Python 字符串, URLconf在其上查找并匹配。进行匹配时将不包括GET或POST请求方式的参数以及域名。
例如,http://www.example.com/myapp/
请求中,URLconf 将查找myapp/。
在http://www.example.com/myapp/?page=3
请求中,URLconf 仍将查找myapp/。
包含其它的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 ...
]
捕获的参数
被包含的URLconf 会收到来自父URLconf 捕获的任何参数
传递额外的选项给视图函数
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’)。
URL 的反向解析
在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的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.year_archive, name='news-year-archive'),
#...
]
模板里获得url:
<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代码中获得url:
from django.core.urlresolvers 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命名空间有两个部分,它们都是字符串:
- 应用命名空间
- 实例命名空间
命名空间也可以嵌套。命名URL’sports:polls:index’ 将在命名空间’polls’中查找’index’,而poll 定义在顶层的命名空间’sports’ 中。
快捷函数
render
render(request, template_name[, context][, context_instance][, content_type][, status][, current_app][, dirs][, using])
必选参数
- request,该request用于生成response
- template_name,要使用的模板的完整名称或者模板名称的一个序列。
可选参数
- context,添加到模板上下文的一个字典。
context_instance
,渲染模板的上下文实例。content_type
,生成的文档要使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值。- status,响应的状态码。默认为200。
- current_app,指示哪个应用包含当前的视图。
- using,用于加载模板使用的模板引擎的名称。
render_to_response
render_to_response(template_name[, context][, context_instance][, content_type][, status][, dirs][, using])
根据一个给定的上下文字典渲染一个给定的目标,并返回渲染后的HttpResponse。
必选参数
- template_name,使用的模板的完整名称或者模板名称的序列。
可选参数
- context,添加到模板上下文中的字典。
content_type
,生成的文档使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值。- status,相应的状态码。默认为200。
- using,加载模板使用的模板引擎的名称。
redirect
redirect(to, [permanent=False, ]*args, **kwargs)
为传递进来的参数返回HttpResponseRedirect 给正确的URL
参数可以是:
- 一个模型:将调用模型的
get_absolute_url()
函数 - 一个视图,可以带有参数:将使用urlresolvers.reverse 来反向解析名称
- 一个绝对的或相对的URL,将原样作为重定向的位置。
get_object_or_404
get_object_or_404(klass, *args, **kwargs)
在一个给定的模型管理器上调用get(),但是引发Http404 而不是模型的DoesNotExist 异常。
必选参数
- klass,获取该对象的一个Model 类,Manager或QuerySet 实例。
- **kwargs,查询的参数,格式应该可以被get() 和filter()接受。
示例:
from django.shortcuts import get_object_or_404
def my_view(request):
my_object = get_object_or_404(MyModel, title__startswith='M',pk=1)
get_list_or_404
get_list_or_404(klass, *args, **kwargs)
返回一个给定模型管理器上filter() 的结果,并将结果映射为一个列表,如果结果为空则返回Http404。
必选参数
- klass,获取该列表的一个Model、Manager 或QuerySet 实例。
- **kwargs,查寻的参数,格式应该可以被get() 和filter() 接受。
示例:
from django.shortcuts import get_list_or_404
def my_view(request):
my_objects = get_list_or_404(MyModel, published=True)
视图装饰器
Django为视图提供了数个装饰器,用以支持相关的HTTP服务。
限制 HTTP 的请求方法
- require_http_methods(request_method_list),限制视图只能服务规定的http方法。
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def my_view(request):
# I can assume now that only GET or POST requests make it this far
# ...
pass
- require_GET(),只允许视图接受GET方法的装饰器。
- require_POST(),只允许视图接受POST方法的装饰器。
- require_safe(),只允许视图接受 GET 和 HEAD 方法的装饰器。 这些方法通常被认为是安全的,因为方法不该有请求资源以外的目的。
内建视图
开发环境中的文件服务器
static.serve(request, path, document_root, show_indexes=False)
在本地的开发环境中,除了你的项目中的静态文件,可能还有一些文件,出于方便,你希望让Django 来作为服务器。serve() 视图可以用来作为任意目录的服务器。(该视图不能用于生产环境,应该只用于开发时辅助使用;在生产环境中你应该使用一个真实的前端Web 服务器来服务这些文件)。
最常见的例子是用户上传文档到MEDIA_ROOT 中。django.contrib.staticfiles
用于静态文件且没有对用户上传的文件做处理,但是你可以通过在URLconf 中添加一些内容来让Django 作为MEDIA_ROOT 的服务器:
from django.conf import settings
from django.views.static import serve
# ... the rest of your URLconf goes here ...
if settings.DEBUG:
urlpatterns += [
url(r'^media/(?P<path>.*)$', serve, {
'document_root': settings.MEDIA_ROOT,
}),
]
注意,这里的代码片段假设你的MEDIA_URL的值为'/media/'
。它将调用serve() 视图,传递来自URLconf 的路径和(必选的)document_root
参数。
因为定义这个URL 模式显得有些笨拙,Django 提供一个小巧的URL 辅助函数static(),它接收MEDIA_URL这样的参数作为前缀和视图的路径如'django.views.static.serve'
。其它任何函数参数都将透明地传递给视图。
错误视图
defaults.page_not_found(request, template_name='404.html')
defaults.server_error(request, template_name='500.html')
defaults.permission_denied(request, template_name='403.html')
defaults.bad_request(request, template_name='400.html')