核心功能
了解更多 Django 框架的其他核心功能 :
一、有条件的内容处理
条件视图处理
HTTP 客户端可以发送许多headers来告诉服务器已经查看到资源的副本了。这通常用在检索网页时,避免发送所有那些已经被检索过的数据。但是,相同的headers可以被用来服务所有的HTTP方法 (POST, PUT, DELETE, 等等)
针对每个从 Django 视图返回的页面(响应),它可能提供了两种HTTP headers:ETag header 和 Last-Modified header。这些 headers 是 HTTP 的可选项。他们可以在视图函数里设置,或者依赖 ConditionalGetMiddleware 中间件来设置 ETag header 。
当客户端下一次请求相同资源时,它可能会发送header,如 If-modified-since 或 If-unmodified-since ,包含它发送后最后一次修改时间,或者 If-match 或者 If-none-match ,包含它发送的最后一个 ETag。如果页面的当前版本与客户端发送的 ETag 匹配,或者如果资源没有被修改,那么就会返回一个304状态,告诉客户端:“资源没有任何变化”,而不是返回所有资源响应。根据这个 header,如果页面发生了修改或者客户端没有匹配 ETag ,会返回 412 状态码。
当你需要更多的控制,你可以使用针对每个视图的条件处理函数。
from django.db import models
class Blog(models.Model):
...
class Entry(models.Model):
blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
published = models.DateTimeField(default=datetime.datetime.now)
...
def latest_entry(request, blog_id):
return Entry.objects.filter(blog=blog_id).latest("published").published
from django.views.decorators.http import condition
@condition(last_modified_func=latest_entry)
def front_page(request, blog_id):
...
仅用于计算一个值的快捷方式
作为常用规则,如果你可以提供函数去同时计算 ETag 和最后的修改时间,你应该这样做。你不知道任何给定的 HTTP 客户端将向你发送哪一个headers,因此需要同时处理这两个headers。然而,有时候只有一个值易于计算,Django 提供的装饰器处理只有 ETag 或 只有 last-modified 的计算。
django.views.decorators.http.etag 和 django.views.decorators.http.last_modified 装饰器和 condition 装饰器一样传递相同的函数类型。它们的签名是这样的:
etag(etag_func)
last_modified(last_modified_func)
我们可以使用其中一个装饰器来编写更早一些的那个只使用last-modified函数的例子:
@last_modified(latest_entry)
def front_page(request, blog_id):
...
...或:
def front_page(request, blog_id):
...
front_page = last_modified(latest_entry)(front_page)
测试两个条件时使用 condition
如果你想测试两个先决条件,那么试着链接 etag 和 last_modified 装饰器可能看起来更好。然而,这会导致错误的行为。
# Bad code. Don't do this!
@etag(etag_func)
@last_modified(last_modified_func)
def my_view(request):
# ...
# End of bad code.
第一个装饰器不知道关于第二个装饰器的任何信息,而且可能回答“这个响应没有被修改”,即使第二个装饰器确定不是那样。condition 装饰器同时使用两个回调函数来执行正确的动作。
二、内容类型和通用关系
内容类型框架
Django 包含了一个 contenttypes 应用程序,它可以跟踪所有安装在你的 Django 项目中的模型,为你的模型提供了一个高级的通用接口。
概况
内容类型应用的核心是 ContentType 模型,它位于 django.contrib.contenttypes.models.ContentType。ContentType 的实例代表和存储了你项目中安装的模型的信息,每当有新的模型安装时,就会自动创建 ContentType 的新实例。
ContentType 的实例有方法用于返回它们所代表的模型类和查询这些模型中的对象。 ContentType 也有一个 自定义管理器,它增加了一些方法,用于处理 ContentType,以及为特定模型获取 ContentType 的实例。
你的模型和 ContentType 之间的关系也可以用来启用你的一个模型实例和你安装的任何模型实例之间的“通用 ”关系。
安装内容类型框架
内容类型框架包含在由 django-admin startproject 创建的默认的 INSTALLED_APPS 列表中,但是如果你已经删除了它,或者你手动设置了 INSTALLED_APPS 列表,你可以通过在 INSTALLED_APPS 配置中添加 ‘django.contrib.contenttypes’ 来启用它。
一般来说,安装内容类型框架是个不错的主意;Django 的其他一些捆绑的应用程序都需要它:
管理应用程序使用它来记录通过管理界面添加或更改的每个对象的历史。
Django 的 认证框架 使用它将用户权限与特定模型绑定。
ContentType 模型
class ContentType
ContentType 的每个实例都有两个字段,这两个字段合在一起,唯一地描述了一个安装的模型。
app_label
模型所属应用程序的名称。这是从模型的 app_label 属性中提取的,并且只包括应用程序的 Python 导入路径的 最后 一部分;例如,django.contrib.contenttypes 就变成了 contenttypes 的 app_label。
model
模型类的名称。
此外,还有以下属性:
name
内容类型的可读名称。这是从模型的 verbose_name 属性中提取的。
让我们看一个例子来了解它是如何工作的。如果你已经安装了 contenttypes 应用程序,然后添加 站点框架 到你的 INSTALLED_APPS 配置中,并运行 manage.py migrate 来安装它,模型 django.contrib.sites.models.Site 将被安装到你的数据库中。与它一起创建一个新的 ContentType 实例,其值如下:
app_label 将被设置为 ‘sites’ (Python 路径 django.contrib.sites 的最后一部分)。
model 将被设置为 ‘site’。
三、简单页面
Django 自带一个可选的“简单页面”应用程序。它可以让你在数据库中存储“简单”的 HTML 内容,并通过 Django 的管理界面和 Python API 为你处理管理。
简单页面是一个有 URL、标题和内容的对象。它可以用于一次性的、特殊情况下的页面,比如“关于”或“隐私政策”页面,你想把这些页面存储在数据库中,但又不想开发一个自定义的 Django 应用。
一个简单页面可以使用自定义模板,也可以使用系统默认的简单页面模板。它可以与一个或多个网站关联。
如果你想把你的内容放在一个自定义模板中,内容字段可以选择留空。
安装
要安装简单页面应用,请按照以下步骤操作:
安装 站点框架,在 INSTALLED_APPS 设置中添加 ‘django.contrib.sites’,如果还没有的话。
同时确保你已经正确地设置 SITE_ID 为配置文件所代表的网站 ID。这通常是 1 (即 SITE_ID = 1,但如果你使用网站框架来管理多个网站,它可能是不同网站的 ID。
将 ‘django.contrib.flatpages’ 添加到你的 INSTALLED_APPS 配置中。
在你的 URLconf 中添加一个条目。例如:
urlpatterns = [
path('pages/', include('django.contrib.flatpages.urls')),
]
或:
将 ‘django.contrib.flatpages.middleware.FlatpageFallbackMiddleware’ 添加到你的 MIDDLEWARE 配置中。
运行命令 manage.py migrate。
四、重定向
Django 自带了一个可选的重定向应用程序。它可以让你在数据库中存储重定向,并为你处理重定向。它默认使用 HTTP 响应状态码 301 Moved Permanently。
安装
要安装重定向应用程序,请按照这些步骤进行:
- 确保 django.contrib.sites 框架 已安装。
- 将 ‘django.contrib.redirects’ 添加到你的 INSTALLED_APPS 配置中。
- 在你的 MIDDLEWARE 配置中添加’django.contrib.redirects.middleware.RedirectFallbackMiddleware’。
- 运行命令 manage.py migrate。
五、信号
Django有一个“信号调度器(signal dispatcher)”,用来帮助解耦的应用获知框架内任何其他地方发生了操作。简单地说,信号允许某些 发送器 去通知一组 接收器 某些操作发生了。当许多代码段都可能对同一事件感兴趣时,信号特别有用。
Django 提供了 内置信号集 使用户代码能够获得 Django 自身某些操作的通知。其中包括一些有用的通知:
- django.db.models.signals.pre_save & django.db.models.signals.post_save
一个模型的 save() 方法被调用之前或之后发出。
- django.db.models.signals.pre_delete & django.db.models.signals.post_delete
一个模型的 delete() 方法或查询结果集的 delete() 方法被调用之前或之后发出。
- django.db.models.signals.m2m_changed
一个模型的 ManyToManyField 更改后发出。
- django.core.signals.request_started & django.core.signals.request_finished
Django 发起或结束一个 HTTP 请求后发出。
六、系统检查框架
系统检查框架是一组验证Django项目的静态检查。 它检测到常见的问题,并提供了如何解决这些问题的提示。 该框架是可扩展的,所以你可以轻松地添加自己的检查。
通过 check 命令来显示的触发检查操作。检查会在大多数命令之前被隐式触发,包括 runserver 和 migrate 。出于性能原因,检查不会作为部署中使用的 WSGI 堆栈的一部分来运行。如果你需要在部署系统上运行系统检查,可以使用 check 来触发他们。
严重的错误将阻止 Django 命令(比如 runserver)运行。小问题将会在控制台上报告出来。如果你已经检查了警告的原因并愿意忽略它,你可以在 settings.py 文件里的 SILENCED_SYSTEM_CHECKS 设置隐藏指定的警告。
编写自定义的检查
框架是可伸缩的,并且允许你编写函数来执行其他你需要的其他检查。举例:
from django.core.checks import Error, register
@register()
def example_check(app_configs, **kwargs):
errors = []
# ... your check logic here
if check_failed:
errors.append(
Error(
'an error',
hint='A hint.',
obj=checked_object,
id='myapp.E001',
)
)
return errors
七、站点框架
Django 自带了一个可选的“站点”框架。它是一个钩子,用于将对象和功能关联到特定的网站上,它是你的 Django 驱动的网站的域名和“啰嗦”名称的保存地。
如果你的单个 Django 安装支持多个站点,并且你需要以某种方式区分这些站点,那么就使用它。
站点框架主要基于这个模型:
class models.Site
储存网站 domain 和 name 属性的模型。
domain
与网站相关的完全合格域名。例如,www.example.com。
name
一个人类可读的“啰嗦”的网站名称。
SITE_ID 配置指定与该特定配置文件相关联的 Site 对象的数据库 ID。如果省略该设置,则 get_current_site() 函数将尝试通过比较 domain 和 request.get_host() 方法中的主机名来获取当前站点。
如何使用这个功能由你决定,但 Django 通过几个约定自动使用它。
八、Django 中的 Unicode
Unicode 数据
Django 处处支持 Unicode 数据。
如果你要编写使用 ASCII 以外编码的数据或模板的应用程序,你需要知道什么。
创建数据库
确保你的数据库被配置成能够存储任意字符串数据。通常,这意味着给它一个 UTF-8 或 UTF-16 的编码。如果你使用更严格的编码——例如,latin1(iso8859-1)——你将无法在数据库中存储某些字符,信息将丢失。
MySQL 用户,请参考 MySQL 手册 ,了解如何设置或更改数据库字符集编码。
PostgreSQL 用户,请参考 PostgreSQL 手册 ,了解以正确编码创建数据库的细节。
SQLite 用户,你不需要做什么。SQLite 一直使用 UTF-8 作为内部编码。
所有 Django 的数据库后端都会自动将字符串转换为合适的编码来与数据库对话。它们也会自动将从数据库中获取的字符串转换为字符串。你甚至不需要告诉 Django 你的数据库使用什么编码:这都是透明的处理。