第二章:视图和URL
2.1第一个Django驱动的页面
- 页面的内容由视图函数(view function)生成,URL 在 URL 配置(URLconf)中指定.
若想把视图函数与特定的 URL 对应起来 - 要使用 URL 配置(URLconf)
正则表达式字符串前面的 'r' 字符。它的目的是告诉 Python,那是“原始字符
串”,不要解释里面的反斜线 - Django 在检查 URL 模式时会把入站 URL 前面的斜线去掉。因此,URL 模式中没有前导斜线。
- 默认情况下,如果请求的 URL 不匹配任何 URL 模式,而且末尾没有斜线,那么 Django 会把它重定向到末尾带斜线的 URL。
2.2django处理请求的过程
- 运行 python manage.py runserver 命令时,manage.py 脚本在内层 mysite 目录中寻找名为 settings.py 的文
件。这个文件中保存着当前 Django 项目的全部配置,各个配置的名称都是大写的,例如 TEMPLATE_DIRS、
DATABASES,等等。其中最重要的设置是 ROOT_URLCONF。它告诉 Django,网站的 URL 配置在哪个 Python 模块
中 - 收到针对某个 URL(假如是 /hello/)的请求时,Django 加载
ROOT_URLCONF 设置指定的 URL 配置;然后按顺序检查 URL 配置中的各个 URL 模式,依次与请求的 URL 比
较,直到找到匹配的模式为止 - 找到匹配的模式之后,调用对应的视图函数,并把一个 HttpRequest 对象作为第一个参数传给视图。(后文
会详述 HttpRequest。)如我们编写的第一个视图所示,视图函数必须返回一个 HttpResponse 对象
2.5Django错误页面信息
- 页面顶部是异常的关键信息:异常的类型和消息(这里是 "unsupported type"),抛出异常的文件,
以及所在的行号。 - 关键信息下面是异常的完整 Python 调用跟踪。这与 Python 命令解释器给出的标准调用跟踪类似,不
过能与之交互。对栈里的每一层(“帧”),Django 都会显示文件名、函数/方法名、行号和那一行的源
码。 - 点击源码所在的行(深灰色),会显示前后数行,为你提供上下文。点击每一帧下面的“Local vars”可
以查看那一帧抛出异常时所有局部变量及其值。这些信息能给调试提供极大的帮助。 - 注意“Traceback”标题旁边的“Switch to copy-and-paste view”文本。点击那些文本之后,调用跟踪会切换
到另一个版本,以便复制粘贴。如果想把异常的调用跟踪分享给他人(例如 Django IRC 或 Django 用
户邮件列表中友善的人),寻求技术支持,可以使用这个版本。 - 切换之后,底部会显示一个“Share this traceback on a public Web site”按钮,只需点击一下就能把调用跟
踪发布到网上。点击那个按钮之后,调用跟踪会发布到 dpaste 网站中,而且会得到一个 URL,便于分
享给其他人。 - 接下来是“Request information”(请求信息)部分,里面包含大量与导致错误的入站 Web 请求有关的信
息:GET 和 POST 信息、cookie 值,以及元信息,如 CGI 首部。附录 F 有一份关于请求对象中所含信息
的完整参考。 - “Request information”部分下面是“Settings”(设置)部分,列出 Django 当前的全部设置。各个设置在
URL和命名空间
- URL 的反向解析:根据Django 视图的标识和将要传递给它的参数的值,获取与之关联的URL。
- 在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
人们强烈希望不要硬编码这些URL(费力、不可扩展且容易产生错误)或者设计一种与URLconf 毫不相关的专门的URL 生成机制,因为这样容易导致一定程度上产生过期的URL -
在需要URL 的地方,对于不同层级,Django 提供不同的工具用于URL 反查:
- 在模板中:使用url 模板标签。
- 在Python 代码中:使用django.core.urlresolvers.reverse() 函数。
- 在更高层的与处理Django 模型实例相关的代码中:使用get_absolute_url() 方法。
- 在使用Django 项目时,一个常见的需求是获得URL 的最终形式,以用于嵌入到生成的内容中(视图中和显示给用户的URL等)或者用于处理服务器端的导航(重定向等)。
- URL 命名空间:URL 命名空间允许你反查到唯一的命名URL 模式,即使不同的应用使用相同的URL 名称
- 因为一个应用的多个实例共享相同的命名URL,命名空间提供了一种区分这些命名URL 的方法。
- 在一个站点上,正确使用URL命名空间的Django 应用可以部署多次
- 一个URL命名空间有两个部分,它们都是字符串(详细见django中文文档URL部分)
-
应用命名空间
:表示你在哪个应用中
- 实例命名空间:表示在哪个视图的方法中(即实例)
- URL 的命名空间使用':' 操作符指定。例如,管理站点应用的主页使用'admin:index'。它表示'admin' 的一个命名空间和'index' 的一个命名URL
-
应用命名空间
第三章 django模版
3.1django模版系统基础
- Django 模板是一些文本字符串,作用是把文档的表现与数据区分开。模板定义一些占位符和基本的逻辑(模板标签),规定如何显示文档。通常,模板用于生成 HTML,不过 Django 模板可以生成任何基于文本的格式。
- 模版标签
- 两对花括号包围的文本(如 {{ person_name }})是变量,意思是“把指定变量的值插入这里”。如何指
定变量的值呢?稍后说明。 - 一对花括号和百分号包围的文本(如 {% if ordered_warranty %})是模板标签。
标签的定义相当宽泛:只要能让模板系统“做些事”的就是标签。 - • 这个示例模板中有一个 for 标签({% for item in item_list %})和一个 if 标签({% if ordered_warranty %})。for 标签的作用与 Python 中的 for 语句很像,用于迭代序列中的各个元素。与你预期的一样,if 标签的作用是编写逻辑判断语句。这里,if 标签检查 ordered_warranty 变量的求值结果是不是 True。如果是,模板系统将显示 {% if
ordered_warranty %} 和 {% else %} 之间的内容;如果不是,模板系统将显示 {% else %} 和 {% endif%} 之间的内容。注意,{% else %} 是可选的。 - 最后,这个模板的第二段包含一个过滤器,这是调整变量格式最为便利的方式。对这个示例中的 {{ship_date|date:"F j, Y" }} 来说,我们把 ship_date 变量传给 date 过滤器,并且为 date 过滤器指定"F j, Y" 参数。date 过滤器使用参数指定的格式格式化日期。过滤器使用管道符号(|)依附,类似于 Unix 管道
- 两对花括号包围的文本(如 {{ person_name }})是变量,意思是“把指定变量的值插入这里”。如何指
- 创建 Template 对象时,模板系统会把原始的模板代码编译成内部使用的优化形式,为渲染做好准备。
- 渲染上下文
- 上下文就是一系列模板变量和相应的值。模板使用上下文填充变量,求值标签。
- Django 查找一个名为 DJANGO_SETTINGS_MODULE 的环境变量,其值是导入 settings.py 的路径。例如,DJANGO_SETTINGS_MODULE 的值可能是 'mysite.settings'(假设 mysite 在 Python 路径中)。执行 python manage.py shell 命令时,它会为你设定 DJANGO_SETTINGS_MODULE。在这些示例中必须使用 python manage.py shell,否则 Django 会抛出异常。
- Django模版中可以按照访问变量的方式访问方法,但是方法必须是无参数的
-
模板系统遇到变量名中的点号时会按照下述顺序尝试查找
- 字典查找(如 foo["bar"])
- 属性查找(如 foo.bar)
- 方法调用(如 foo.bar())
- 列表索引查找(如 foo[2])
- 模板系统将使用第一个可用的类型,这是一种短路逻辑。点号查找可以嵌套多层。
-
如何处理无效变量:一般来说,如果变量不存在,模板系统在变量处插入引擎的 string_if_invalid 配置选项。这个选项的默认
值为一个空字符串。就是什么都没有
3.4django模版系统
- Django 的模板系统自带了一些内置的标签和过滤器
- if/else ;如果需要通过括号指明优先级,应该使用嵌套的 if 标签。不支持使用括号控制操作的顺序。如果觉得有必要
使用括号,可以考虑在模板外部执行逻辑,然后通过专用的模板变量传入结果。 - {% for athlete in athlete_list reversed %} 加入reverse反向迭代列表
- 因此 for 标签支持一个可选的 {% empty %} 子句,用于定义列表为空时显示的内容。
- 在 {% for %} 循环内部,可以访问一个名为 forloop 的模板变量。这个变量有几个属性,通过它们可以获知
循环进程的一些信息- • forloop.counter 的值是一个整数,表示循环的次数。这个属性的值从 1 开始,因此第一次循环时,
forloop.counter 等于 1。下面举个例子: - • forloop.counter0 与 forloop.counter 类似,不过是从零开始的。第一次循环时,其值为 0。
- • forloop.revcounter 的值是一个整数,表示循环中剩余的元素数量。第一次循环时,forloop.revcounter 的值是序列中要遍历的元素总数。最后一次循环时,forloop.revcounter 的值为 1。
- • forloop.revcounter0 与 forloop.revcounter 类似,不过索引是基于零的。第一次循环时,forloop.revcounter0 的值是序列中元素数量减去一。最后一次循环时,forloop.revcounter0 的值为 0。
- • forloop.first 是个布尔值,第一次循环时为 True。需要特殊处理第一个元素时很方便:
- • forloop.counter 的值是一个整数,表示循环的次数。这个属性的值从 1 开始,因此第一次循环时,
- {% ifequal %} 标签比较两个值,如果相等,显示 {% ifequal %} 和 {% endifequal %} 之间的内容。
过滤器
- ,模板过滤器是在显示变量之前调整变量值的简单方式。过滤器使用管道符号指定,过滤器可以串
接,即把一个过滤器的输出传给下一个过滤器,过滤器的参数放在冒号之后,始终放在双引号内- 如下{{ bio|truncatewords:"30" }}
- 过滤器详见附录
django模版加载机制
- 为了从文件系统中加载模板,Django 提供了便利而强大的 API,力求去掉模板加载调用和模板自身的冗余。若想使用这个模板加载 API,首先要告诉框架模板的存储位置
-
配置setting.py的模版项
- • BACKEND 的值是一个点分 Python 路径,指向实现 Django 模板后端 API 的模板引擎类
- • DIRS 定义一个目录列表,模板引擎按顺序在里面查找模板源文件。
- • APP_DIRS 设定是否在安装的应用中查找模板。按约定,APPS_DIRS 设为 True 时,Django Templates 会在INSTALLED_APPS 中的各个应用里查为“templates”的 子目录。这样,即使 DIRS 为空,模板引擎还能查找应用模板。
- • OPTIONS 是一些针对后端的设置
-
为了找到模板在文件系统中的位置,get_template() 按下列顺序查找模版
- • 如果 APP_DIRS 的值是 True,而且使用 DTL,在当前应用中查找“templates”目录。
- • 如果在当前应用中没找到模板,get_template() 把传给它的模板名称添加到 DIRS 中的各个目录后面,
按顺序在各个目录中查找。假如 DIRS 的第一个元素是 '/home/django/mysite/templates',上述
get_template() 调用查找的模板是 /home/django/mysite/templates/current_datetime.html。 - • 如果 get_template() 找不到指定名称对应的模板,抛出 TemplateDoesNotExist 异常
-
render()
- render() 的返回值是一个 HttpResponse 对象,
- render() 的第一个参数是请求对象,第二个参数是模板名称,第三个单数可选,是一个字段,用于创建传给
模板的上下文。如果不指定第三个参数,render() 使用一个空字典
-
include模版标签
- 这个标签的作用是引入另一个模板的内容。它的参数是要引入的模板的名称,可以是变量,也可以是硬编码
的字符串(放在引号里,单双引号都行)。 - 模板引擎加载 current_datetime.html 模板时,发现有 {% extends %} 标签,意识到这是一个
子模板,因此立即加载父模板,即这里的 base.html。
加载父模板时,模板引擎发现 base.html 中有三个 {% block %} 标签,然后使用子模板中的内容替换。因此,
将使用 {% block title %} 中定义的标题和 {% block content %} 中定义的内容
- 这个标签的作用是引入另一个模板的内容。它的参数是要引入的模板的名称,可以是变量,也可以是硬编码
-
模版加载原理
- 模板引擎加载 current_datetime.html 模板时,发现有 {% extends %} 标签,意识到这是一个
子模板,因此立即加载父模板,即这里的 base.html。加载父模板时,模板引擎发现 base.html 中有三个 {% block %} 标签,然后使用子模板中的内容替换。因此,
将使用 {% block title %} 中定义的标题和 {% block content %} 中定义的内容 - 继承不影响模板的上下文。也就是说,继承树中的任何模板都能访问上下文中的每一个模板变量。
- 模板引擎加载 current_datetime.html 模板时,发现有 {% extends %} 标签,意识到这是一个
-
模版继承指导方针
- • 如果模板中有 {% extends %},必须是模板中的第一个标签。否则,模板继承不起作用。
- • 一般来说,基模板中的 {% block %} 标签越多越好。记住,子模板无需定义父模板中的全部块,因此
可以为一些块定义合理的默认内容,只在子模板中覆盖需要的块。钩子多总是好的。 - • 如果发现要在多个模板中重复编写相同的代码,或许说明应该把那些代码移到父模板中的一个 {%
block %} 标签里。 - • 如果需要从父模板中的块里获取内容,使用 {{ block.super }},这是一个“魔法”变量,提供父模板中
渲染后的文本。向块中添加内容,而不是完全覆盖时就可以这么做。 - • 在同一个模板中不能为多个 {% block %} 标签定义相同的名称。之所以有这个限制,是因为 block 标
签是双向的。即,block 标签不仅标识供填充的空位,还用于定义填充父模板中空位的内容。如果一
个模板中有两个同名的块,那么父模板就不知道使用哪个块里的内容。 - • 传给 {% extends %} 的模板名称使用与 get_template() 相同的方法加载。即,模板在 DIRS 设置定义的
目录中,或者在当前 Django 应用的“templates”目录里。 - •多数情况下,{% extends %} 的参数是字符串,不过如果直到运行时才知道父模板的名称,也可以用变
量。通过这一点可以做些动态判断
-
- if/else ;如果需要通过括号指明优先级,应该使用嵌套的 if 标签。不支持使用括号控制操作的顺序。如果觉得有必要
第四章 Django模型
-
使用python定义模型
- python manage.py check check 命令运行 Django 系统检查框架,即验证 Django 项目的一系列静态检查
- python manage.py sqlmigrate books 0001 sqlmigrate 命令的参数是迁移名称,输出
的结果是对应的 SQL
-
基本的数据访问
- 保存对象道数据库
- 使用 Django 模型 API 创建的对象不会自动保
存,只能自己动手调用 save() 方法,如果想在一步中创建对象并保存到数据库中,使用 objects.create() 方法。 - 插入和更新数据
- 实例化模型类不会接触数据库。为了把记录保存到数据库中,要调用 save() 方法,更新直接修改查询对象就可以
- 查询
- 想查找数据就应该使用相应的模型
- 然后,访问 objects 属性,objects叫管理器,管理器负责
所有“表层”数据操作 - 最后,调用 all() 方法。这是 objects 管理器的一个方法,返回数据库中的所有行。虽然返回的对象
看似一个列表,但其实是一个查询集合(QuerySet)——表示数据库中一系列行的对象。
- 过滤数据
- filter() 方法过滤数据,如下:filter(name='Apress') ;filter() 的关键字参数转换成相应的 SQL WHERE 子句,多个参数转换成 SQL AND 子句,查找操作默认使用 SQL = 运算符做精确匹配查找。
- 如下句:name__contains="press" ;Django 使用双下划线表示“魔法”操作。这里,
Django 把 __contains 部分转换成 SQL LIKE 语句 - get(name="Apress")方法用于检索单个对象,只返回一个对象
- order_by("name") 用于排序,如果想根据多个字段排序(以第一个字段排不出顺序时使用第二个字段),提供多个参数,反向排序。方法是在字段名称前面加上“-”(减号)模型类的元类可以制定查询的默认顺序
在模型类中加入 下句class Meta:ordering = ['name'] - 查询可以链式进行
- 只查找固定数量的行可以使用切片,注意,不支持使用负数,切片结果如下
order_by('name')[0:2] = ORDER BY name OFFSET 0 LIMIT 2; - objects.filter(id=52).update(name='Apress Publishing')update() 方法可以在任何 QuerySet 对象上调用,这意味着可以通过它批量编辑多个记录,update() 方法有返回值,是一个整数,表示修改的记录数量
- 从数据库中删除一个对象,只需在对象上调用 delete() 方法,还可以在任何 QuerySet 对象上调用 delete() 方法,批量删除对象
- 为了防止不小心把表中的数据都删除,想删除表中的一切数据时,Django 要求必须显式调用 all() 方法 objects.all().delete() ,如果只想删除部分数据,无需调用 all() 方法
- 使用 Django 模型 API 创建的对象不会自动保
- 保存对象道数据库
第五章Django管理后台
-
使用django管理后台
- 管理界面限制只让授信的网站管理员访问,用于添加、编辑和删除网站内容
第六章:Django表单
- 从请求对象中获取信息
- 请求对象就是HttpRequest对象,该对象有一些关于URL的信息
1. request.path 完整的路径不含域名
2. request.get_host()。 域名(主机名)
3. request.get_full_path()。包含查询字符串的路径。例如“/hello/?print=true”
4. is_secure() 通过 HTTPS 访问时为 True,否则为 False
- 请求对象就是HttpRequest对象,该对象有一些关于URL的信息
- 在视图中一定要使用这些属性或方法,不能硬编码 URL,例如。return HttpResponse("Welcome to the page at %s" % request.path)
- 关于请求的其他信息:request.META 的值是一个 Python 字典,包含请求的所有 HTTP 首部,例如用户的 IP 地址和用户代理(user agent,通常是 Web 浏览器的名称和版本)。 注意,具体包含哪些首部取决于用户发送了什么首部,以及Web 服务器返回了什么首部,该字典中常用键如下
- HTTP_REFERER:入站前的 URL(可能没有)。(注意,要使用错误的拼写,即 REFERER。
- HTTP_USER_AGENT:浏览器的用户代理(可能没有)。例如:"Mozilla/5.0 (X11; U; Linux i686; frFR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17
- REMOTE_ADDR:客户端的 IP 地址,例如 "12.345.67.89"。(如果请求经由代理,这个首部的值可能是一组 IP 地址,以逗号分隔,例如 "12.345.67.89,23.456.78.90"。
- HttpRequest 对象还有两个属性包含用户提交的信息:request.GET 和 request.POST。这两个属性的值都是类似字典的对象,分别用于获取 GET 和 POST 数据。 POST数据一般由 HTML表单提交,而 GET 数据既可以来自表单,也可以来自页面 URL 中的查询字符串
- 不应该相信用户提交的任何数据,甚至可以假设用户根本没有提交任何数据。如果不做这一项检查,提交空表单会导致视图抛出 KeyError,要对用户提交的数据进行验证
1. 验证分两步,第一步在试图层判断是否数据合法,合法则方形,不合法应该返回到表单页面,然后在页面进行错误提示,可以这样写:
2. if 'q' in request.GET and request.GET['q']: 视图验证
3. return render(request, 'search_form.html', {'error': True}) 重新返回到表单然后重新渲染模版
4. {% if error %}
<p style="color: red;">Please submit a search term.</p>
{% endif %}- 创建一个联系表单
1. Django 自带了一个表单库,django.forms
2.
- 创建一个联系表单
第七章:高级URL和视图
-
URL 配置小技巧
-
具名分组:在高级用法中,可以使用具名的正则表达式分组捕获 URL 片段,通过关键字参数把片段传给视图
1. 在 Python 正则表达式中,具名分组的句法是 (? P<name>pattern),其中 name 是分组的名称,pattern 是要匹配的模式。
-
具名分组:在高级用法中,可以使用具名的正则表达式分组捕获 URL 片段,通过关键字参数把片段传给视图
- 可以使用不指定关键字的url模式:
类似于:url(r'^reviews/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.review_detail),
匹配条目: views.month_archive(request, '2005', '03') 函数 - ** 捕获的值以关键字参数传给视图**:
url(r'^reviews/(?P<year>[0-9] {4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$',views.review_detail), - URL匹配分组算法
1. URL 配置解析器解析正则表达式中具名分组和非具名分组所 采用的算法如下:
1. 如果有具名分组,使用具名分组,忽略非具名分组。
2. 否则,以位置参数传递所有非具名分组 - URL 配置搜索的范围
URL 配置搜索的是所请求的 URL,而且把它视作普通的 Python 字符串。搜索的范围不包括 GET 或 POST 参
数,抑或域名。例如对 http://www.example.com/myapp/ 的请求,URL 配置只查找 myapp/;对 http://www.example.com/myapp/?page=3 的请求,URL 配置只查找 myapp/。URL 配置不关心请求方法。也就是说,相同
URL 的所有请求方法(POST、GET、HEAD,等等)都交由同一个视图函数处理 - 错误处理
- 找不到匹配所请求 URL 的正则表达式或有异常抛出时,Django 会调用一个错误处理视图,具体使用的视图由四个参数指定。这四个参数是
• handler404
• handler500
• handler403
• handler400
- 找不到匹配所请求 URL 的正则表达式或有异常抛出时,Django 会调用一个错误处理视图,具体使用的视图由四个参数指定。这四个参数是
-
反向解析URL
- 在 Django 项目中经常需要获取 URL 的最终形式,这么做是为了在生成的内容中嵌入 URL(视图和静态资源的 URL、呈现给用户的 URL,等等),或者在服务器端处理导航流程(重定向等)。
此时,一定不能硬编码 URL(费时、不可伸缩,而且容易出错),或者参照 URL 配置创造一种生成 URL 的机制,因为这样容易导致线上 URL 失效。也就是说,我们需要一种不自我重复的机制。
这种机制的一个优点是,改进 URL 设计之后无需在项目的源码中大范围搜索,替换掉过期的 URL。目前,我们能获取的信息有负责处理 URL 的视图标识(即视图名称),以及查找正确 URL 所需的视图参数类型(位置参数或关键字参数)和值。
Django 提供了一种方案,只需在 URL 映射中设计 URL。我们为其提供 URL 配置,然后可以双向使用:
• 从用户(浏览器)请求的 URL 开始,这个方案能调用正确的 Django 视图,并从 URL 中提取可能需要
的参数及其值,传给视图。
• 从 Django 视图对应的标识以及可能传入的参数值开始,获取相应的 URL。第一点就是我们目前所讨论的处理方式。第二点称为反向解析 URL、反向匹配 URL、反向查找 URL 或 URL
反转。- 反向匹配就是通过给某个urlconf加入全项目唯一的name来反来查找URL
- Django 在不同的层中提供了执行 URL 反转所需的工具:
• 在模板中,使用 url 模板标签。
• 在 Python 代码中,使用 django.core.urlresolvers.reverse() 函数。
• 在处理 Django 模型实例 URL 相关的高层代码中,使用 get_absolute_url() 方法 - 为了执行 URL 反转,要像前述示例那样为 URL 模式命名。URL 模式的名称可以包含任何字符串,而不限定
于必须是有效的 Python 标识符。为 URL 模式命名时,要确保不与其他应用中的名称冲突。如果你把 URL 模
式命名为 comment,而另一个应用也这么做,在模板中使用这个名称时就无法确定该生成哪个 URL。为了减
少冲突,可以为 URL 模式的名称加上前缀,比如说使用应用程序的名称。我们建议使用 myapp-comment,而
不是 comment
- 在 Django 项目中经常需要获取 URL 的最终形式,这么做是为了在生成的内容中嵌入 URL(视图和静态资源的 URL、呈现给用户的 URL,等等),或者在服务器端处理导航流程(重定向等)。
-
URL命名空间
- URL 命名空间在反转具名 URL 模式时具有唯一确定性,即便不同的应用使用相同的名称也不怕。鉴于此,第三方应用最好始终把 URL 放在命名空间中。类似地,URL 命名空间在部署多个应用程序实例时也能正确反转 URL。也就是说,同一个应用程序的多个实例使用相同的 URL 模式名称,而通过命名空间可以把它们区分开。正确使用 URL 命名空间的 Django 应用程序可以在同一个网站中多次部署。例如,django.contrib.admin 中有个 AdminSite 类,可以轻易部署多个管理后台。URL 命名空间分为两部分,而且都是字符串:
1. 应用命名空间。指明应用的名称。一个应用的每个实例都具有相同的应用命名空间。例如,你可能猜
到了,Django 管理后台的应用命名空间是 admin。
2. 实例命名空间。标识具体的应用程序实例。实例命名空间在整个项目范围内应该是唯一的。不过,实例命名空间可以与应用命名空间相同,供应用的默认实例使用。例如,Django 管理后台实例的默认实例命名空间是 admin。
命名空间中的 URL 使用 : 运算符指定。例如,管理后台的主页使用 admin:index 引用。其中,admin 是命名空间,index 是 URL 的名称。
命名空间还可以嵌套。 members:reviews:index 在命名空间 members 中查找命名空间 reviews,再在里面查找index URL
- URL 命名空间在反转具名 URL 模式时具有唯一确定性,即便不同的应用使用相同的名称也不怕。鉴于此,第三方应用最好始终把 URL 放在命名空间中。类似地,URL 命名空间在部署多个应用程序实例时也能正确反转 URL。也就是说,同一个应用程序的多个实例使用相同的 URL 模式名称,而通过命名空间可以把它们区分开。正确使用 URL 命名空间的 Django 应用程序可以在同一个网站中多次部署。例如,django.contrib.admin 中有个 AdminSite 类,可以轻易部署多个管理后台。URL 命名空间分为两部分,而且都是字符串:
-
反转命名空间中的URL(review:index)
解析命名空间中的 URL 时(如 reviews:index),Django 先分解完全限定的名称,然后尝试做下述查找- 首先,Django 查找有没有匹配的应用命名空间(这里的 reviews)。为此,会产出那个应用的实例列表
- 如果有这么一个应用实例,Django 返回它的 URL 解析程序。当前应用可以通过请求的一个属性指定。预期有多个部署实例的应用应该在处理的请求上设定current_app 属性
- 当前应用也可以手动指定,方法是作为参数传给 reverse() 函数
- 如果没有当前应用,Django 查找默认的应用实例。默认应用实例是指实例命名空间与应用命名空间匹配的实例(在这里是指名为 reviews 的 reviews 实例)
- 如果没有默认的应用实例,Django 选中最后部署的应用实例,而不管实例的名称
- 如果第 1 步找不到匹配的应用命名空间,Django 直接把它视作实例命名空间查找
- URL 命名空间和引入的 URL 配置
把引入的 URL 配置放入命名空间中有两种方式- 在 URL 模式中为 include() 提供应用和实例命名空间,例如url(r'^reviews/', include('reviews.urls',namespace='author-reviews',app_name='reviews')),上述代码把 reviews.urls 中定义的 URL 放在应用命名空间 reviews 中,放在实例命名空间 author-reviews
- 第二种方式是,引入包含命名空间数据的对象。如果使用 include() 引入一组 url() 实例,那个对象中的 URL 都添加到全局命名空间中然而,include() 的参数还可以是一个三元素元组,其内容如下:(<list of url() instances>, <application namespace>, <instance namespace>),例如url(r'^reviews/', include((reviews_patterns, 'reviews', 'author-reviews')))上述代码把指定的 URL 模式引入指定的应用和实例命名空间中。例如,部署的 Django 管理后台是 AdminSite
的实例。AdminSite 对象有个 urls 属性,它的值是一个三元素元组,包含相应管理后台的所有 URL 模式,以
及应用命名空间 'admin' 和管理后台实例的名称。部署管理后台实例时,引入项目的 urlpatterns 中的就是
这个 urls 属性。
记得要把一个元组传给 include()。如果直接传入三个参数,例如 include(reviews_patterns, 'reviews',
'author-reviews'),Django 不会抛出错误,但是根据 include() 的签名,'reviews' 是实例命名空间,'author-reviews' 是应用命名空间,而正确的顺序应该反过来。