# Django 3.2.11.dev 文档

# 站点地图框架

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` 类可以代表你的 Weblog 的所有条目，而另一个可以代表你的事件日历中的所有事件。

在最简单的情况下，所有这些部分都被归纳到一个 `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()` 是一个返回 sequence 或 `QuerySet` 对象的方法。返回的对象将被传递给对应于站点地图属性的任何可调用方法（`location`，`lastmod`，`changefreq` 和 `priority`）。
- `lastmod` 应该返回一个 `datetime`。
- 本例中没有 `location` 方法，但你可以提供该方法来指定对象的 URL。默认情况下，`location()` 调用每个对象的 `get_absolute_url()` 并返回结果。

## `Sitemap` 类参考

class `Sitemap`

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

  `items`

    必须的。 一个返回对象的 sequence 或 `QuerySet` 的方法。框架并不关心它们是什么类型的对象，重要的是这些对象被传递给 `location()`、`lastmod()`、`changefreq()` 和 `priority()` 方法。

  `location`

    可选的。 方法或属性。

    如果是方法，则应返回 `items()` 返回的给定对象的绝对路径。

    如果它是一个属性，它的值应该是一个字符串，代表一个绝对路径，用于 `items()` 返回的 每一个 对象。

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

    - 对的：`'/foo/bar/'`
    - 错的：`'example.com/foo/bar/'`
    - 错的：`'https://example.com/foo/bar/'`

    如果没有提供 `location`，框架将调用 `items()` 返回的每个对象的 `get_absolute_url()` 方法。

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

  `lastmod`

    可选的。 方法或属性。

    如果它是一个方法，它应该接受一个参数——一个由 `items()` 返回的对象——并以 `datetime` 返回该对象最后修改的日期／时间。

    如果是属性，其值应该是 `datetime`，代表 `items()` 返回的 每一个 对象的最后修改日期／时间。

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

  `paginator`

    可选的。

    这个属性返回一个 `Paginator` 的 `items()`。如果你批量生成网站地图，你可能想覆盖这个属性作为一个缓存属性，以避免多次调用 `items()`。

  `changefreq`

    可选的。 方法或属性。

    如果它是一个方法，它应该接受一个参数——一个由 `items()` 返回的对象——并以字符串形式返回该对象的变化频率。

    如果是属性，其值应该是一个字符串，代表 `items()` 返回的 每一个 对象的变化频率。

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

    - `'always'`
    - `'hourly'`
    - `'daily'`
    - `'weekly'`
    - `'monthly'`
    - `'yearly'`
    - `'never'`
  `priority`

    可选的。 方法或属性。

    如果它是一个方法，它应该接受一个参数——一个由 `items()` 返回的对象——并以字符串或浮点数的形式返回该对象的优先级。

    如果它是一个属性，它的值应该是一个字符串或浮点数，代表 `items()` 返回的 每一个 对象的优先级。

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

  `protocol`

    可选的。

    该属性定义了网站地图中 URL 的协议（`'http'` 或 `'https'`）。如果没有设置，则使用请求网站地图的协议。如果站点地图是在请求之外建立的，则默认为 `'http'`。

  `limit`

    可选的。

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

  `i18n`

    可选的。

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

  `languages`
    New in Django 3.2.

    可选的。

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

  `alternates`
    New in Django 3.2.

    可选的。

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

  `x_default`
    New in Django 3.2.

    可选的。

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

## 捷径

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

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

  `django.contrib.sitemaps.GenericSitemap` 类允许你通过传递一个至少包含一个 `queryset` 条目的字典来创建一个站点地图。该查询结果集将用于生成站点地图的项目。它也可以有一个 `date_field` 条目，为从 `queryset` 中检索的对象指定一个日期字段。这将用于生成的站点地图中的 `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}),
        path('sitemap-<section>.xml', views.sitemap, {'sitemaps': sitemaps},
             name='django.contrib.sitemaps.views.sitemap'),
    ]

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

如果你的一个网站地图有超过 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'
        }),
        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` 是指向每个站点地图的绝对 URL 的列表。

### Sitemap

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

- `alternates`
- `changefreq`
- `item`
- `lastmod`
- `location`
- `priority`

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

Changed in Django 3.2:

增加了 `alternates` 属性。

为每个 URL 添加了 `item` 属性，以便更灵活地定制模板，如 Google news sitemaps 。假设 Sitemap 的 `items()` 会返回一个带有 `publication_data` 和 `tags` 字段的项目列表，类似这样就可以生成一个 Google News 兼容的网站地图。

    <?xml version="1.0" encoding="UTF-8"?>
    <urlset
      xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
      xmlns:news="http://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>

## 通知谷歌

当你的网站地图发生变化时，你可能想“ping”一下谷歌，让它知道要重新索引你的网站。站点地图框架提供了一个函数来实现这个功能： `django.contrib.sitemaps.ping_google()`。

`ping_google`(sitemap_url=None, ping_url=PING_URL, sitemap_uses_https=True)

  `ping_google` 接受这些可选的参数：

  - `sitemap_url` - 通往网站站点地图的绝对路径（例如： `'/sitemap.xml'`）。如果没有提供这个参数，`ping_google` 将尝试通过在 URLconf 中进行反向查找来获取网站地图。
  - `ping_url` - 默认为谷歌的 Ping 工具：https://www.google.com/webmasters/tools/ping。
  - `sitemap_uses_https` - 如果你的网站使用 `http` 而不是 `https`，设置为 `False`。

  `ping_google()` 如果不能确定你的站点地图 URL，会引发异常 `django.contrib.sitemaps.SitemapNotFound`。

首先向谷歌注册！

`ping_google()` 命令只有在你在 Google Search Console 注册了你的网站时才有效。

调用 `ping_google()` 的一个有用的方法是在模型的 `save()` 方法：

    from django.contrib.sitemaps import ping_google

    class Entry(models.Model):
        # ...
        def save(self, force_insert=False, force_update=False):
            super().save(force_insert, force_update)
            try:
                ping_google()
            except Exception:
                # Bare 'except' because we could get a variety
                # of HTTP-related exceptions.
                pass

然而，一个更有效的解决方案是在定时脚本中调用 `ping_google()`，或者其他一些预定任务。该函数向谷歌的服务器发出 HTTP 请求，所以你可能不想在每次调用 `save()` 时引入网络开销。

### 通过 `manage.py` 通知谷歌

`django-admin ping_google [sitemap_url]`

一旦将站点地图应用程序添加到你的项目中，你也可以使用 `ping_google` 管理命令通知谷歌：

    python manage.py ping_google [/sitemap.xml]

`--sitemap-uses-http```

如果你的网站地图使用 `http` 而不是 `https`，请使用这个选项。