简单页面应用

Django 自带一个可选的“简单页面”应用程序。它可以让你在数据库中存储“简单”的 HTML 内容,并通过 Django 的管理界面和 Python API 为你处理管理。

A flatpage is an object with a URL, title and content. Use it for one-off, special-case pages, such as "About" or "Privacy Policy" pages, that you want to store in a database but for which you don't want to develop a custom Django application.

一个简单页面可以使用自定义模板,也可以使用系统默认的简单页面模板。它可以与一个或多个网站关联。

如果你想把你的内容放在一个自定义模板中,内容字段可以选择留空。

安装

要安装简单页面应用,请按照以下步骤操作:

  1. 安装 站点框架,在 INSTALLED_APPS 设置中添加 'django.contrib.sites',如果还没有的话。

    同时确保你已经正确地设置 SITE_ID 为配置文件所代表的网站 ID。这通常是 1 (即 SITE_ID = 1,但如果你使用网站框架来管理多个网站,它可能是不同网站的 ID。

  2. 'django.contrib.flatpages' 添加到你的 INSTALLED_APPS 配置中。

那么无论是:

  1. 在你的 URLconf 中添加一个条目。例如:

    urlpatterns = [
        path("pages/", include("django.contrib.flatpages.urls")),
    ]
    

或:

  1. 'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware' 添加到你的 MIDDLEWARE 配置中。
  2. 运行命令 manage.py migrate

工作方式

manage.py migrate 在数据库中创建两个表。django_flatpagedjango_flatpage_sitesdjango_flatpage 是一个查找表,将一个 URL 映射到标题和一堆文本内容。django_flatpage_sites 将一个简单页面与一个网站关联起来。

使用 URLconf

有几种方法可以在你的 URLconf 中包含简单页面。你可以为简单页面指定一个特定的路径:

urlpatterns = [
    path("pages/", include("django.contrib.flatpages.urls")),
]

你也可以把它设置成一个“catchall”模式。在这种情况下,重要的是将该模式放在其他 urlpatterns 的最后:

from django.contrib.flatpages import views

# Your other patterns here
urlpatterns += [
    re_path(r"^(?P<url>.*/)$", views.flatpage),
]

警告

如果你将 APPEND_SLASH 设置为 False,你必须删除 catchall 模式中的斜杠,否则没有尾部斜杠的简单页面将不会被匹配。

另一种常见的设置是对有限的已知页面集使用简单页面,并对网址进行硬编码,所以你可以用 url 模板标签来引用它们:

from django.contrib.flatpages import views

urlpatterns += [
    path("about-us/", views.flatpage, {"url": "/about-us/"}, name="about"),
    path("license/", views.flatpage, {"url": "/license/"}, name="license"),
]

使用中间件

FlatpageFallbackMiddleware 可以完成所有的工作。

class FlatpageFallbackMiddleware

每当任何 Django 应用出现 404 错误时,这个中间件都会检查简单页面数据库中所请求的 URL,作为最后的手段。具体来说,它检查给定 URL 的简单页面,其网站 ID 对应于:setting:SITE_ID 配置。

如果它找到了一个匹配,就按照这个算法:

  • 如果简单页面有自定义模板,它就加载该模板。否则,它会加载模板 flatpages/default.html
  • 它给该模板传递了一个上下文变量 flatpage,也就是简单页面对象。它使用 RequestContext 来渲染模板。

如果产生的 URL 指向有效的简单页面,中间件只会添加尾部的斜线和重定向(通过查看 APPEND_SLASH 配置)。重定向是永久性的(301 状态码)。

如果没有找到匹配的请求,则继续照常处理。

中间件只有在 404 时才会被激活——而不是 500 或任何其他状态码的响应。

简单页面不会应用视图中间件

因为 FlatpageFallbackMiddleware 只有在 URL 解析失败并产生 404 之后才会应用,所以它返回的响应不会应用任何 视图中间件 方法。只有通过正常 URL 解析成功路由到视图的请求才会应用视图中间件。

注意 MIDDLEWARE 的顺序很重要。一般来说,你可以把 FlatpageFallbackMiddleware 放在列表的最后。这意味着它将在处理响应时首先运行,并确保任何其他响应处理中间件看到的是真正的简单页面响应而不是 404。

关于中间件的更多内容,请阅读 中间件文档

确保你的 404 模板工作

请注意 FlatpageFallbackMiddleware 只有在另一个视图成功产生 404 响应后才会介入。如果另一个视图或中间件类试图产生 404,但最后却引发了一个异常,那么响应将变成 HTTP 500(“内部服务器错误”),并且 FlatpageFallbackMiddleware 将不会试图服务一个简单页面。

如何添加、更改和删除简单页面

警告

Permissions to add or edit flatpages should be restricted to trusted users. Flatpages are defined by raw HTML and are not sanitized by Django. As a consequence, a malicious flatpage can lead to various security vulnerabilities, including permission escalation.

通过管理界面

如果你已经激活了 Django 的自动管理界面,你应该会在管理索引页上看到一个“简单页面”栏目。编辑简单页面就像编辑系统中的其他对象一样。

FlatPage 模型有一个 enable_comments 字段,contrib.flatpages 没有使用,但对你的项目或第三方应用程序可能有用。它不会出现在管理界面中,但你可以通过为 FlatPage 注册一个自定义的 ModelAdmin 来添加它:

from django.contrib import admin
from django.contrib.flatpages.admin import FlatPageAdmin
from django.contrib.flatpages.models import FlatPage
from django.utils.translation import gettext_lazy as _


# Define a new FlatPageAdmin
class FlatPageAdmin(FlatPageAdmin):
    fieldsets = [
        (None, {"fields": ["url", "title", "content", "sites"]}),
        (
            _("Advanced options"),
            {
                "classes": ["collapse"],
                "fields": [
                    "enable_comments",
                    "registration_required",
                    "template_name",
                ],
            },
        ),
    ]


# Re-register FlatPageAdmin
admin.site.unregister(FlatPage)
admin.site.register(FlatPage, FlatPageAdmin)

通过 Python API

class FlatPage

简单页面由一个标准的 Django 模型 来表示,它位于 django/contrib/flatpages/models.py 中。你可以通过 Django 数据库 API 来访问简单页面对象。

检查是否有重复的简单页面网址。

如果你通过自己的代码来添加或修改简单页面,你很可能要检查同一站点内是否有重复的简单页面 URL。管理中使用的简单页面表单可以执行这种验证检查,可以从 django.contrib.flatpages.forms.FlatpageForm 中导入,并在你自己的视图中使用。

简单页面模板

默认情况下,简单页面是通过模板 flatpages/default.html 来渲染的,但是你可以为某个特定的简单页面覆盖这个模板:在管理中,一个名为“高级选项”的折叠式字段集(点击可以展开)包含了一个指定模板名称的字段。如果你是通过 Python API 创建一个简单页面,你可以将模板名称设置为 template_name 对象上的字段 FlatPage

创建 flatpages/default.html 模板是你的责任;在你的模板目录下,创建一个 flatpages 目录,其中包含一个文件 default.html

简单模板被传递一个单一的上下文变量 flatpage,也就是简单页面对象。

下面是一个示例 flatpages/default.html 模板:

<!DOCTYPE html>
<html>
<head>
<title>{{ flatpage.title }}</title>
</head>
<body>
{{ flatpage.content }}
</body>
</html>

由于你已经在管理页面中输入了原始 HTML,所以 flatpage.titleflatpage.content 都在模板中被标记为 不需要 自动 HTML 转义

获取模板中的 FlatPage 对象列表

简单页面应用提供了一个模板标签,允许你在 :ref:`当前站点 <hooking-into-current-site-from-views>`上迭代所有可用的简单应用。

和所有的自定义模板标签一样,在使用它之前,你需要 加载其自定义标签库。加载库后,你可以通过 get_flatpages 标签来检索当前所有的简单页面。

{% load flatpages %}
{% get_flatpages as flatpages %}
<ul>
    {% for page in flatpages %}
        <li><a href="{{ page.url }}">{{ page.title }}</a></li>
    {% endfor %}
</ul>

显示 registration_required 简单页面

默认情况下,get_flatpages 模板标签只显示标记为 registration_required = False 的页面。如果你想显示受注册保护的页面,你需要使用 for 子句指定一个经过认证的用户。

例如:

{% get_flatpages for someuser as about_pages %}

如果你提供了一个匿名用户, get_flatpages 将与你没有提供用户的行为相同——即,它将只向你显示公共的简单页面。

通过基础 URL 限制简单页面

一个可选的参数,starts_with,可以用来限制返回的页面以特定的基本 URL 开头。这个参数可以以字符串的形式传递,也可以以一个变量的形式从上下文中解析。

例如:

{% get_flatpages '/about/' as about_pages %}
{% get_flatpages about_prefix as about_pages %}
{% get_flatpages '/about/' for someuser as about_pages %}

django.contrib.sitemaps 整合

class FlatPageSitemap

sitemaps.FlatPageSitemap 类查看所有为当前 SITE_ID 定义的公开可见的 flatpages (参见 站点文档),并在站点地图中创建一个条目。这些条目只包括 location 属性——不包括 lastmodchangefreqpriority

例如

下面是一个使用 FlatPageSitemap 的 URLconf 的例子:

from django.contrib.flatpages.sitemaps import FlatPageSitemap
from django.contrib.sitemaps.views import sitemap
from django.urls import path

urlpatterns = [
    # ...
    # the sitemap
    path(
        "sitemap.xml",
        sitemap,
        {"sitemaps": {"flatpages": FlatPageSitemap}},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]