# Django 5.2.8 documentation

# 站点地图框架

Django 自带了一个高级站点地图生成框架来创建 sitemap XML 文件。

## 概况

站点地图是你网站上的一个 XML 文件，它告诉搜索引擎索引器你页面的变化频率，以及某些页面相对于你网站上其他页面的“重要性”。这些信息有助于搜索引擎对你的网站进行索引。

Django 站点地图框架通过让你用 Python 代码表达这些信息以自动创建这个 XML 文件。

它的工作原理很像 Django 的 联合框架。要创建一个站点地图，写一个 `Sitemap` 类，并将其指向你的 URLconf。

## 安装

要安装站点地图应用，请按照以下步骤进行：

1. 将 `'django.contrib.sitemaps'` 添加到你的 `INSTALLED_APPS` 配置中。

2. 确保你的 `TEMPLATES` 配置中包含一个 `DjangoTemplates` 后端，其 `APP_DIRS` 选项设置为 `True`。默认有一个后端，所以你只需要改变这个配置就可以了。

3. 确保你已经安装了 `sites framework`。

（注意：站点地图应用不会安装任何数据库表。它需要进入 `INSTALLED_APPS` 的唯一原因是为了让 `Loader()` 模板加载器能够找到默认模板。）

## 初始化

views.sitemap(request, sitemaps, section=None, template_name='sitemap.xml', content_type='application/xml')

要在你的 Django 网站上激活站点地图的生成，在你的 URLconf 中添加这一行：

    from django.contrib.sitemaps.views import sitemap

    path(
        "sitemap.xml",
        sitemap,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.sitemap",
    )

这告诉 Django 在客户端访问 `/sitemap.xml` 时建立一个站点地图。

站点地图文件的名称并不重要，但位置很重要。搜索引擎只对当前URL级别及以下的站点地图链接进行索引。例如，如果 `sitemap.xml` 位于你的根目录下，它可以引用您网站中的任何URL。但是，如果您的站点地图位于 `/content/sitemap.xml`，则只能引用以 `/content/` 开头的 URL。

sitemap 视图需要一个额外的、必要的参数：`{'sitemaps': sitemaps}`。`sitemaps` 应该是一个字典，它将一个简短的章节标签（例如，`blog` 或 `news`）映射到它的 `Sitemap` 类（例如，`BlogSitemap` 或 `NewsSitemap`）。也可以映射到一个 `Sitemap` 类的 实例 （例如，`BlogSitemap(some_var)`）。

## `Sitemap` 类

`Sitemap` 类是一个 Python 类，在你的网站地图中代表一个条目的“部分”。例如，一个 `Sitemap` 类可以代表你的博客的所有条目，而另一个则可以代表你的事件日历中的所有事件。

在最简单的情况下，所有这些部分都被归纳到一个 `sitemap.xml` 中，但也可以使用该框架生成一个站点地图索引来引用单个站点地图文件，每个部分一个。（参见下面的 创建一个站点地图索引 ）。

`Sitemap` 类必须是 `django.contrib.sitemaps.Sitemap` 子类。它们可以存在于你代码库的任何地方。

## 一个例子

让我们假设你有一个博客系统，有一个 `Entry` 模型，你希望你的网站地图包括所有链接到你的个人博客条目。下面是你的网站地图类的样子：

    from django.contrib.sitemaps import Sitemap
    from blog.models import Entry

    class BlogSitemap(Sitemap):
        changefreq = "never"
        priority = 0.5

        def items(self):
            return Entry.objects.filter(is_draft=False)

        def lastmod(self, obj):
            return obj.pub_date

注意：

- `changefreq` 和 `priority` 分别是用作 `<changefreq>` 和 `<priority>` 元素的类属性。它们可以作为函数调用，就像本例中的 `lastmod` 一样。

- `items()` is a method that returns a sequence or `QuerySet` of objects. The objects returned will get passed to any callable methods corresponding to a sitemap property (`location`, `lastmod`, `changefreq`, and `priority`).

- `lastmod` 应该返回一个 `datetime`。

- There is no `location` method in this example, but you can provide it in order to specify the URL for your object. By default, `location` calls `get_absolute_url()` on each object and returns the result.

## `Sitemap` 类参考

class Sitemap

  `Sitemap` 类可以定义以下方法／属性。

  items()

    Required. A method that returns a sequence or `QuerySet` of objects. The framework doesn't care what type of objects they are; all that matters is that these objects get passed to the `location`, `lastmod`, `changefreq` and `priority` methods.

  location

    可选的。 方法或属性。

    If it's a method, it should return the absolute path for a given object as returned by `items()`.

    If it's an attribute, its value should be a string representing an absolute path to use for every object returned by `items()`.

    在这两种情况下，“绝对路径”指的是不包含协议或域名的 URL。例如：

    - 好的：`'/foo/bar/'`

    - 不好的：`'example.com/foo/bar/'`

    - 不好的：`'https://example.com/foo/bar/'`

    If `location` isn't provided, the framework will call the `get_absolute_url()` method on each object as returned by `items`.

    如果要指定 `'http'` 以外的协议，请使用 `protocol`。

  lastmod

    可选的。 方法或属性。

    If it's a method, it should take one argument -- an object as returned by `items()` -- and return that object's last-modified date/time as a `datetime`.

    If it's an attribute, its value should be a `datetime` representing the last-modified date/time for every object returned by `items()`.

    如果站点地图中的所有项目都有一个 `lastmod`，那么由 `views.sitemap()` 生成的站点地图将有一个 `Last-Modified` 头，等于最新的 `lastmod`。你可以激活 `ConditionalGetMiddleware`，让 Django 对请求做出适当的响应，并提供 `If-Modified-Since` 头，防止发送没有变化的站点地图。

  paginator

    可选的。

    This property returns a `Paginator` for `items()`. If you generate sitemaps in a batch you may want to override this as a cached property in order to avoid multiple `items()` calls.

  changefreq

    可选的。 方法或属性。

    If it's a method, it should take one argument -- an object as returned by `items()` -- and return that object's change frequency as a string.

    If it's an attribute, its value should be a string representing the change frequency of every object returned by `items()`.

    `changefreq` 的可能值，无论你是使用方法还是属性，都是：

    - `'always'`

    - `'hourly'`

    - `'daily'`

    - `'weekly'`

    - `'monthly'`

    - `'yearly'`

    - `'never'`

  priority

    可选的。 方法或属性。

    If it's a method, it should take one argument -- an object as returned by `items()` -- and return that object's priority as either a string or float.

    If it's an attribute, its value should be either a string or float representing the priority of every object returned by `items()`.

    `priority` 的示例值：`0.4`，`1.0`。页面的默认优先级是 `0.5`。更多信息请参见 sitemaps.org documentation 。

  protocol

    可选的。

    该属性定义了站点地图中 URL 的协议（`'http'` 或 `'https'`）。如果未设置，则使用请求站点地图时使用的协议。如果站点地图是在没有请求上下文的情况下构建的，默认值为 `'https'`。

  limit

    可选的。

    该属性定义了网站地图每一页所包含的 URL 的最大数量。其值不应超过默认值 `50000`，这是 Sitemaps protocol 中允许的上限。

  i18n

    可选的。

    一个布尔属性，用于定义该网站地图的 URL 是否应使用所有的 `LANGUAGES` 生成。默认值是 `False`。

  languages

    可选的。

    启用 `i18n` 时用于生成备用链接的 语言代码 sequence。默认为 `LANGUAGES`。

  alternates

    可选的。

    一个布尔属性。当与 `i18n` 结合使用时，生成的 URL 将有一个备用链接列表，使用 hreflang attribute 指向其他语言版本。默认为 `False`。

  x_default

    可选的。

    一个布尔属性。当 `True` 时，由 `alternates` 生成的备用链接将包含一个 `hreflang="x-default"` 回退条目，其值为 `LANGUAGE_CODE`。默认值是 `False`。

  get_latest_lastmod()

    可选项。 一个方法，返回由 `lastmod` 返回的最新值。此函数用于向 Sitemap 索引上下文变量 添加 `lastmod` 属性。

    默认情况下，`get_latest_lastmod()` 返回：

    - 如果 `lastmod` 是一个属性：`lastmod`。

    - If `lastmod` is a method: The latest `lastmod` returned by calling the method with all items returned by `items()`.

  get_languages_for_item(item)

    可选项。 一个方法，返回显示该项的语言代码序列。默认情况下，`get_languages_for_item()` 返回 `languages`。

## 捷径

站点地图框架为常见的情况提供了一个方便的类：

class GenericSitemap(info_dict, priority=None, changefreq=None, protocol=None)

  `django.contrib.sitemaps.GenericSitemap` 类允许您通过传递一个至少包含 `queryset` 条目的字典来创建一个站点地图。这个查询集将用于生成站点地图的项。它还可以有一个 `date_field` 条目，用于指定从 `queryset` 中检索的对象的日期字段。这将在生成的站点地图中用于 `lastmod` 属性和 `get_latest_lastmod()` 方法。

  `priority`、`changefreq` 和 `protocol` 关键字参数允许为所有 URL 指定这些属性。

### 例如

下面是一个使用 `GenericSitemap` 的 URLconf 例子：

    from django.contrib.sitemaps import GenericSitemap
    from django.contrib.sitemaps.views import sitemap
    from django.urls import path
    from blog.models import Entry

    info_dict = {
        "queryset": Entry.objects.all(),
        "date_field": "pub_date",
    }

    urlpatterns = [
        # some generic view using info_dict
        # ...
        # the sitemap
        path(
            "sitemap.xml",
            sitemap,
            {"sitemaps": {"blog": GenericSitemap(info_dict, priority=0.6)}},
            name="django.contrib.sitemaps.views.sitemap",
        ),
    ]

## 静态视图的站点地图

通常情况下，你希望搜索引擎爬虫能够索引那些既不是对象详情页也不是简单页面的视图。解决的办法是在 `items` 中明确列出这些视图的 URL 名称，并在站点地图的 `location` 方法中调用 `reverse()`。例如：

    # sitemaps.py
    from django.contrib import sitemaps
    from django.urls import reverse

    class StaticViewSitemap(sitemaps.Sitemap):
        priority = 0.5
        changefreq = "daily"

        def items(self):
            return ["main", "about", "license"]

        def location(self, item):
            return reverse(item)

    # urls.py
    from django.contrib.sitemaps.views import sitemap
    from django.urls import path

    from .sitemaps import StaticViewSitemap
    from . import views

    sitemaps = {
        "static": StaticViewSitemap,
    }

    urlpatterns = [
        path("", views.main, name="main"),
        path("about/", views.about, name="about"),
        path("license/", views.license, name="license"),
        # ...
        path(
            "sitemap.xml",
            sitemap,
            {"sitemaps": sitemaps},
            name="django.contrib.sitemaps.views.sitemap",
        ),
    ]

## 创建站点地图索引

views.index(request, sitemaps, template_name='sitemap_index.xml', content_type='application/xml', sitemap_url_name='django.contrib.sitemaps.views.sitemap')

站点地图框架还能够创建一个站点地图索引，该索引能够引用单独的站点地图文件，每个部分在你的 `sitemaps` 字典中定义一个。唯一不同的用法是：

- 你在 URLconf 中使用了两个视图： `django.contrib.sitemaps.views.index()` 和 `django.contrib.sitemaps.views.sitemap()`。

- `django.contrib.sitemaps.views.sitemap()` 视图应该采用 `section` 关键字作为参数。

下面是上面例子的相关 URLconf 行的样子：

    from django.contrib.sitemaps import views

    urlpatterns = [
        path(
            "sitemap.xml",
            views.index,
            {"sitemaps": sitemaps},
            name="django.contrib.sitemaps.views.index",
        ),
        path(
            "sitemap-<section>.xml",
            views.sitemap,
            {"sitemaps": sitemaps},
            name="django.contrib.sitemaps.views.sitemap",
        ),
    ]

这将自动生成一个 `sitemap.xml` 文件，同时引用 `sitemap-flatpages.xml` 和 `sitemap-blog.xml`。`Sitemap` 类和 `sitemaps` 字典完全没有变化。

If all sitemaps have a `lastmod` returned by `get_latest_lastmod()` the sitemap index will have a `Last-Modified` header equal to the latest `lastmod`.

如果你的一个网站地图有超过 50,000 个 URL，你应该创建一个索引文件。在这种情况下，Django 会自动对网站地图进行分页，索引也会反映出来。

如果你没有使用普通的站点地图视图——例如，如果它是用缓存装饰器包装的——你必须为你的站点地图视图命名，并将 `sitemap_url_name` 传给索引视图：

    from django.contrib.sitemaps import views as sitemaps_views
    from django.views.decorators.cache import cache_page

    urlpatterns = [
        path(
            "sitemap.xml",
            cache_page(86400)(sitemaps_views.index),
            {"sitemaps": sitemaps, "sitemap_url_name": "sitemaps"},
        ),
        path(
            "sitemap-<section>.xml",
            cache_page(86400)(sitemaps_views.sitemap),
            {"sitemaps": sitemaps},
            name="sitemaps",
        ),
    ]

## 自定义模板

如果你希望为网站上的每个站点地图或站点地图索引使用不同的模板，你可以通过 URLconf 向 `sitemap` 和 `index` 视图传递一个 `template_name` 参数来指定它。

    from django.contrib.sitemaps import views

    urlpatterns = [
        path(
            "custom-sitemap.xml",
            views.index,
            {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
            name="django.contrib.sitemaps.views.index",
        ),
        path(
            "custom-sitemap-<section>.xml",
            views.sitemap,
            {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
            name="django.contrib.sitemaps.views.sitemap",
        ),
    ]

这些视图返回 `TemplateResponse` 实例，允许你在渲染前轻松定制响应数据。更多细节，请看 TemplateResponse 文档。

### 上下文变量

在自定义 `index()` 和 `sitemap()` 视图的模板时，可以依赖以下上下文变量。

### 索引

变量 `sitemaps` 是一个包含每个站点地图的 `location` 和 `lastmod` 属性的对象列表。每个 URL 具有以下属性：

- `location`：站点地图的位置（URL 和页面）。

- `lastmod`：由每个站点地图的 `get_latest_lastmod()` 方法填充。

### Sitemap

变量 `urlset` 是一个应该出现在站点地图中的 URL 列表，每个 URL 都会暴露出 `Sitemap` 类中定义的属性。

- `alternates`

- `changefreq`

- `item`

- `lastmod`

- `location`

- `priority`

当 `i18n` 和 `alternates` 被启用时，`alternates` 属性可用。它是一个其他语言版本的列表，包括可选的 `x_default` 回退，对于每个 URL。每个候补是一个字典，有 `location` 和 `lang_code` 键。

The `item` attribute has been added for each URL to allow more flexible customization of the templates, such as Google news sitemaps. Assuming Sitemap's `items()` would return a list of items with `publication_data` and a `tags` field something like this would generate a Google News compatible sitemap:

    <?xml version="1.0" encoding="UTF-8"?>
    <urlset
      xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
      xmlns:news="https://www.google.com/schemas/sitemap-news/0.9">
    {% spaceless %}
    {% for url in urlset %}
      <url>
        <loc>{{ url.location }}</loc>
        {% if url.lastmod %}<lastmod>{{ url.lastmod|date:"Y-m-d" }}</lastmod>{% endif %}
        {% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %}
        {% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
        <news:news>
          {% if url.item.publication_date %}<news:publication_date>{{ url.item.publication_date|date:"Y-m-d" }}</news:publication_date>{% endif %}
          {% if url.item.tags %}<news:keywords>{{ url.item.tags }}</news:keywords>{% endif %}
        </news:news>
       </url>
    {% endfor %}
    {% endspaceless %}
    </urlset>