进入 View 了

如果处理过程这时候还在继续的话,处理器会调用 view function。Django 中的 Views 不很严格因为它只需要满足几个条件:

  • 必须可以被调用。
  • 必须接受 django.http.HttpRequest 的实例作为第一位置参数。
  • 必须能产生一个异常或返回 django.http.HttpResponse 的一个实例。

除了这些,你就可以天马行空了。尽管如此,一般来说,views 会使用 Django 的 database API 来创建,检索,更新和删除数据库的某些东西,还会加载并渲染一个模板来呈现一些东西给最终用户。

模板

Django 的模板系统有两个部分:一部分是给设计师使用的混入少量其它东西的 HTML,另一部分是给程序员使用纯 Python。

从一个 HTML 作者的角度,Django 的模板系统非常简单,需要知道的仅有三个结构:

  • 变量引用。在模板中是这样: {{ foo }}。
  • 模板过滤。在上面的例子中使用过滤竖线是这样:{{ foo|bar }}。通常这 用来格式化输出(比如:运行 Textile,格式化日期等等)。
  • 模板标签。是这样:{% baz %}。这是模板的“逻辑”实现的地方,你可以 {% if foo %},{% for bar in foo %},等等,if 和 for 都是模板标签。

变量引用以一种非常简单的方式工作。如果你只是要打印变量,只要 {{ foo }},模板系统就会输出它。这里唯一的复杂情况是 {{ foo.bar }},这时模板系 统按顺序尝试几件事:

  1. 首先它尝试一个字典方式的查找,看看 foo['bar'] 是否存在。如果存在, 则它的值被输出,这个过程也随之结束。
  2. 如果字典查找失败,模板系统尝试属性查找,看看 foo.bar 是否存在。同 时它还检查这个属性是否可以被调用,如果可以,调用之。
  3. 如果属性查找失败,模板系统尝试把它作为列表索引进行查找。

如果所有这些都失败了,模板系统输出配置 TEMPLATE_STRING_IF_INVALID 的值,默认是空字符串。

模板过滤就是简单的 Python functions,它接受一个值和一个参数,返回一个新的值。比如,date 过滤用一个 Python datetime 对象作为它的值,一个标准的 strftime 格式化字符串作为它的参数,返回对 datetime 对象应用了格式化字符 串之后的结果。

模板标签用在事情有一点点复杂的地方,它是你了解 Django 的模板系统是如何真正工作的地方。

Django 模板的结构

在内部,一个 Django 模板体现为一个 “nodes” 集合,它们都是从基本的 django.template.Node 类继承而来。Nodes 可以做各种处理,但有一个共同点: 每一个 Node 必须有一个叫做 render 的方法,它接受的第二个参数(第一个参 数,显然是 Node 实例)是 django.template.Context 的一个实例,这是一个类似于字典的对象,包含所有模板可以获得的变量。Node 的 render 方法必须返回 一个字符串,但如果 Node 的工作不是输出(比如,它是要通过增加,删除或修 改传入的 Context 实例变量中的变量来修改模板上下文),可以返回空字符串。

Django 包含许多 Node 的子类来提供有用的功能。比如,每个内置的模板标签都 被一个 Node 的子类处理(比如,IfNode 实现了 if 标签,ForNode 实现了 for 标签,等等)。所有内置标签可以在 django.template.defaulttags 找到。

实际上,上面介绍的所有模板结构都是某种形式的 Nodes,纯文本也不异常。变 量查找由 VariableNode 处理,出于自然,过滤也应用在 VariableNode 上,标 签是各种类型的 Nodes,纯文本是一个 TextNode。

一般来说,一个 view 渲染一个模板要经过下面的步骤,依次是:

  1. 加载需要渲染的模板。这是由 django.template.loader.get_template 完成的,它能利用这许多方法中的任意一个来定位需要的模板文件。 get_template 函数返回一个 django.template.Template 实例,其中包含经过解析的模板和用到的方法。
  2. 实例化一个 Context 用来渲染模板。如果用的是 Context 的子类 django.template.RequestContext,那么附带的上下文处理函数就会自动添加在 view 中没有定义的变量。Context 的构建器方法用一个键/值对的字 典(对于模板,它将变为名/值变量)作为它唯一的参数,RequestContext 则用 HttpRequest 的一个实例和一个字典。
  3. 调用 Template 实例的 render 方法,Context 对象作为第一个位置参数。

Template 的 render 方法的返回值是一个字符串,它由 Template 中所有 Nodes 的 render 方法返回的值连接而成,调用顺序为它们出现在 Template 中的顺序。

关于 Response,一点点

一旦一个模板完成渲染,或者产生了其它某些合适的输出,view 就会负责产生一 个 django.http.HttpResponse 实例,它的构建器接受两个可选的参数:

  • 一个作为 response 主体的字符串(它应该是第一位置参数,或者是关键字 参数 content)。大部分时间,这将作为渲染一个模板的输出,但不是必须 这样,在这里你可以传入任何有效的 Python 字符串。
  • 作为 response 的 Content-Type header 的值(它应该是第二位置参数, 或者是关键字参数 mine_type)。如果没有提供这个参数,Django 将会使 用配置中 DEFAULT_MIME_TYPE 的值和 DEFAULT_CHARSET 的值,如果你没有 在 Django 的全局配置文件中更改它们的话,分别是 “text/html” 和 “utf-8”。
异常

如果 view 函数,或者其中的什么东西,发生了异常,那么 get_response(我知 道我们已经花了些时间深入 views 和 templates,但是一旦 view 返回或产生异常,我们仍将重拾处理器中间的 get_response 方法)将遍历它的 _exception_middleware 实例变量并调用那里的每个方法,传入 HttpResponse 和这个 exception 作为参数。如果顺利,这些方法中的一个会实例化一个 HttpResponse 并返回它。

这时候有可能还是没有得到一个 HttpResponse,这可能有几个原因:

  • view 可能没有返回值。
  • view 可能产生了异常但没有一个 middleware 能处理它。
  • 一个 middleware 方法试图处理一个异常时自己又产生了一个新的异常。

这时候,get_response 会回到自己的异常处理机制中,它们有几个层次:

  1. 如果 exception 是 Http404 并且 DEBUG 设置为 True,get_response 将 执行 view django.views.debug.technical_404_response,传入 HttpRequest 和 exception 作为参数。这个 view 会展示 URL resolver 试图匹配的模式信息。
  2. 如果 DEBUG 是 False 并且异常是 Http404,get_response 会调用 URL resolver 的 resolve_404 方法。这个方法查看 URL 配置以判断哪一个 view 被指定用来处理 404 错误。默认是 django.views.defaults.page_not_found,但可以在 URL 配置中给 handler404 变量赋值来更改。
  3. 对于任何其它类型的异常,如果 DEBUG 设置为 True,get_response 将执 行 view django.views.debug.technical_500_response,传入 HttpRequest 和 exception 作为参数。这个 view 提供了关于异常的详细 信息,包括 traceback,每一个层次 stack 中的本地变量,HttpRequest 对象的详细描述和所有无效配置的列表。
  4. 如果 DEBUG 是 False,get_response 会调用 URL resolver 的 resolve_500 方法,它和 resolve_404 方法非常相似,这时默认的 view 是 django.views.defaults.server_error,但可以在 URL 配置中给 handler500 变量赋值来更改。

此外,对于除了 django.http.Http404 或 Python 内置的 SystemExit 之外的任 何异常,处理器会给调度者发送信号 got_request_exception,在返回之前,构建一个关于异常的描述,把它发送给列在 Django 配置文件的 ADMINS 配置中的每一个人。

现在,无论 get_response 在哪一个层次上发生错误,它都会返回一个 HttpResponse 实例,因此我们回到处理器的主要部分。一旦它获得一个 HttpResponse 它做的第一件事就是遍历它的 _response_middleware 实例变量并 应用那里的方法,传入 HttpRequest 和 HttpResponse 作为参数。

finally:
# Reset URLconf for this thread on the way out for complete
# isolation of request.urlconf
urlresolvers.set_urlconf(None) try:
# Apply response middleware, regardless of the response
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
response = self.apply_response_fixes(request, response)

注意对于任何想改变点什么的 middleware 来说,这是它们的最后机会。

一旦 middleware 完成了最后环节,处理器将给调度者发送 信号 request_finished,对与想在当前的 request 中执行的任何东西来说,这是最后的调用。监听这个信号的处理者会清空并释放任何使用中的资源。比如,Django 的 request_finished 监听者会关闭所有数据库连接。

这件事发生以后,处理器会构建一个合适的返回值送返给实例化它的任何东西 (现在,是一个恰当的 mod_python response 或者一个 WSGI 兼容的 response,这取决于处理器)并返回。

这就是 Django 如何处理一个 request。

【转】请求处理机制其三:view层与模板解析的更多相关文章

  1. ZendFramework-2.4 源代码 - 关于MVC - View层 - 在模板内渲染子模板

    <?php // 方式一: // 1.在模板内直接编写如下内容即可 $viewModel = new ViewModel(); $viewModel->setTemplate('album ...

  2. 【转】请求处理机制其二:Django中间件的解析

    Middleware 开始工作了 get_response 做的第一件事就是遍历处理器的 _request_middleware 实例变量并调用其中的每一个方法,传入 HttpRequest 的实例作 ...

  3. DAO层,Service层,Controller层、View层协同工作机制

    转自 http://www.blogdaren.com/post-2024.html DAO层:DAO层主要是做数据持久层的工 作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计D ...

  4. 浅析Yii2的view层设计

    Yii2.0的view层提供了若干重要的功能:assets资源管理,widgets小组件,layouts布局... 下面将通过对Yii2.0代码直接进行分析,看一下上述功能都是如何实现的,当然细枝末节 ...

  5. 《ASP.NET MVC 5 破境之道》:第一境 ASP.Net MVC5项目初探 — 第三节:View层简单改造

    第一境 ASP.Net MVC5项目初探 — 第三节:View层简单改造 MVC默认模板的视觉设计从MVC1到MVC3都没有改变,比较陈旧了:在MVC4中做了升级,好看些,在不同的分辨率下,也能工作得 ...

  6. ASP.Net请求处理机制初步探索之旅 - Part 3 管道

    开篇:上一篇我们了解了一个ASP.Net页面请求的核心处理入口,它经历了三个重要的入口,分别是:ISAPIRuntime.ProcessRequest().HttpRuntime.ProcessReq ...

  7. 【单页应用之通信机制】view之间应该如何通信

    前言 在单页应用中,view与view之间的通信机制一直是一个重点,因为单页应用的所有操作以及状态管理全部发生在一个页面上 没有很好的组织的话很容易就乱了,就算表面上看起来没有问题,事实上会有各种隐忧 ...

  8. iOS应用架构谈(三):View层的组织和调用方案(下)

    iOS客户端应用架构看似简单,但实际上要考虑的事情不少.本文作者将以系列文章的形式来回答iOS应用架构中的种种问题,本文是其中的第二篇,主要讲View层的组织和调用方案.下篇主要讨论做View层架构的 ...

  9. iOS应用架构谈(二):View层的组织和调用方案(中)

    iOS客户端应用架构看似简单,但实际上要考虑的事情不少.本文作者将以系列文章的形式来回答iOS应用架构中的种种问题,本文是其中的第二篇,主要讲View层的组织和调用方案.中篇主要讨论MVC.MVCS. ...

随机推荐

  1. mac下sublime 配置查看源码

    sublime及package control的安装查看之前一篇文章:http://www.cnblogs.com/xdwa/p/5805101.html 安装ctags 安装完毕package co ...

  2. Spring AOP中的动态代理

    0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  Spring AOP中的动态代理机制 2.1  ...

  3. cygwin 运行窗口程序

    首先, 默认安装的cygwin是不能运行窗口程序的 比如,一段python窗口程序: import * from tkinter Tk() mainloop() 如果使用命令行: python3 py ...

  4. Unity3d Hololens MR开发入门

    一.Hololens概述 Hololens有以下特性 1.空间映射借助微软特殊定制的全息处理单元(HPU),HoloLens 实现了对周边环境的快速扫描和空间匹配.这保证了 HoloLens能够准确地 ...

  5. Vue.js 系列教程 ①

    原文:intro-to-vue-1-rendering-directives-events 译者:nzbin 如果要我用一句话描述使用 Vue 的经历,我可能会说“它如此合乎常理”或者“它提供给我需要 ...

  6. oracle 12c安装详细教程

    数据库下载:www.orcale.com访问官网自行下载. 一,将下载好的两个压缩包在同一目录中进行解压(文件目录尽量用英文) 解压后如下使用管理员身份运行setup安装程序 注意:对于学习阶段,这一 ...

  7. 都能读懂的css3 3D变形效果

    css3 3D变形效果 CSS3 transform3D变形 transform的含义是:改变,使-变形:转换 三维变换使用基于二维变换的相同属性,如果您熟悉二维变换,你们发现3D变形的功能和2D变换 ...

  8. C++ 头文件系列(iosfwd)

    简介 输入输出历来都是语言的重要部分,在C++中,该库也是占据了相当大的一部分. C++的输入输出库是其遵循面向对象设计的结果,并结合了泛型编程. 以下是这些库类的关系图(箭头标示继承,白框表示摸板, ...

  9. Android jni 编程1(对基本类型字符串的操作)

    最近一直在学安卓的jni,主要参考的是黑马程序员的视频教程,讲的确实不错. 那就自己总结一下吧,算是对学习的复习. 这篇博客也主要参考了这位博主:http://www.cnblogs.com/acti ...

  10. iOS动画案例(2) 仿网易新闻标题动画

      由于产品的需要,做了一个和网易新闻标题类似的动画效果,现在新闻类的APP都是采用这样的动画效果,来显示更多的内容.先看一下动画效果:   由于这个动画效果在很多场合都有应用,所以我专门封装了一个控 ...