站点地图框架 — Django 文档

来自菜鸟教程
Django/docs/3.1.x/ref/contrib/sitemaps
跳转至:导航、​搜索

站点地图框架

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

概览

站点地图是您网站上的一个 XML 文件,它告诉搜索引擎索引器您的页面更改的频率以及某些页面相对于您网站上的其他页面的“重要性”。 此信息有助于搜索引擎为您的网站编制索引。

Django 站点地图框架通过让您在 Python 代码中表达此信息来自动创建此 XML 文件。

它的工作原理很像 Django 的 联合框架 。 要创建站点地图,请编写一个 Sitemap 类并在您的 URLconf 中指向它。


安装

要安装站点地图应用程序,请按照下列步骤操作:

  1. 'django.contrib.sitemaps' 添加到您的 :setting:`INSTALLED_APPS` 设置。
  2. 确保您的 :setting:`TEMPLATES` 设置包含一个 DjangoTemplates 后端,其 APP_DIRS 选项设置为 True。 默认情况下它就在那里,因此如果您更改了该设置,则只需更改它。
  3. 确保您已安装 站点框架

(注意:站点地图应用程序不安装任何数据库表。 它需要进入 :setting:`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。

站点地图视图需要一个额外的必需参数:{'sitemaps': sitemaps}sitemaps 应该是一个将短节标签(例如 blognews)映射到其 Sitemap 类(例如 [ X137X] 或 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

注意:

  • changefreqpriority 分别是 <changefreq><priority> 元素对应的类属性。 它们可以作为函数调用,如示例中的 lastmod
  • items() 是一种返回对象的 序列QuerySet 的方法。 返回的对象将传递给与站点地图属性对应的任何可调用方法(locationlastmodchangefreqpriority)。
  • lastmod 应该返回一个 datetime
  • 此示例中没有 location 方法,但您可以提供它以指定对象的 URL。 默认情况下, location() 在每个对象上调用 get_absolute_url() 并返回结果。


Sitemap 类参考

class Sitemap

Sitemap 类可以定义以下方法/属性:

items

必需。 返回对象的 序列 QuerySet 的方法。 框架并不关心它们是什么 type 对象; 重要的是这些对象被传递到 location()lastmod()changefreq()priority()方法。

location

可选。 方法或属性。

如果它是一个方法,它应该返回由 items() 返回的给定对象的绝对路径。

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

在这两种情况下,“绝对路径”是指不包含协议或域的 URL。 例子:

如果未提供 location,则框架将调用 items() 返回的每个对象上的 get_absolute_url() 方法。

要指定 'http' 以外的协议,请使用 protocol

lastmod

可选。 方法或属性。

如果它是一个方法,它应该接受一个参数——一个由 items() 返回的对象——并返回该对象的最后修改日期/时间作为一个 datetime

如果它是一个属性,它的值应该是一个 datetime,表示 items() 返回的 every 对象的最后修改日期/时间。

如果站点地图中的所有项目都有 lastmod,则由 views.sitemap() 生成的站点地图将有一个 Last-Modified 标头,等于最新的 lastmod ]。 您可以激活 ConditionalGetMiddleware 以使 Django 正确响应带有 If-Modified-Since 标头的请求,这将阻止发送未更改的站点地图。

changefreq

可选。 方法或属性。

如果它是一个方法,它应该接受一个参数——一个由 items() 返回的对象——并将该对象的更改频率作为字符串返回。

如果它是一个属性,它的值应该是一个字符串,表示 items() 返回的 every 对象的更改频率。

changefreq 的可能值,无论您使用方法还是属性,都是:

  • 'always'

  • 'hourly'

  • 'daily'

  • 'weekly'

  • 'monthly'

  • 'yearly'

  • 'never'

priority

可选。 方法或属性。

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

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

priority 的示例值:0.41.0。 页面的默认优先级为0.5。 有关更多信息,请参阅 sitemaps.org 文档

protocol

可选的。

此属性定义站点地图中 URL 的协议('http''https')。 如果未设置,则使用请求站点地图的协议。 如果站点地图是在请求上下文之外构建的,则默认值为 'http'

limit

可选的。

此属性定义站点地图每个页面上包含的最大 URL 数。 其值不应超过50000的默认值,这是站点地图协议中允许的上限。

i18n

可选的。

一个布尔属性,用于定义是否应使用所有 :setting:`LANGUAGES` 生成此站点地图的 URL。 默认值为 False


快捷方式

站点地图框架为常见情况提供了一个便利类:

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

django.contrib.sitemaps.GenericSitemap 类允许您通过传递一个字典来创建站点地图,该字典必须至少包含一个 queryset 条目。 此查询集将用于生成站点地图的项目。 它还可能有一个 date_field 条目,为从 queryset 检索的对象指定日期字段。 这将用于生成的站点地图中的 lastmod 属性。

prioritychangefreqprotocol 关键字参数允许为所有 URL 指定这些属性。

示例

下面是一个使用 GenericSitemapURLconf 示例:

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 行的样子:

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-flatpages.xmlsitemap-blog.xmlsitemap.xml 文件。 Sitemap 类和 sitemaps dict 根本没有改变。

如果您的站点地图之一包含超过 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'),
]

模板定制

如果您希望为站点上可用的每个站点地图或站点地图索引使用不同的模板,您可以通过将 template_name 参数传递给 sitemapindex 视图来指定它URLconf:

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 列表。


网站地图

变量 urlset 是应该出现在站点地图中的 URL 列表。 每个 URL 公开在 Sitemap 类中定义的属性:

  • changefreq
  • item
  • lastmod
  • location
  • priority

为每个 URL 添加了 item 属性,以允许更灵活地自定义模板,例如 Google 新闻站点地图 。 假设站点地图的 items() 将返回一个包含 publication_data 和一个 tags 字段的项目列表,类似这样的内容将生成一个与 Google 新闻兼容的站点地图:

<?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 谷歌

当您的站点地图更改时,您可能希望“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 - 默认为 Google 的 Ping 工具:https://www.google.com/webmasters/tools/ping。

  • sitemap_uses_https - 如果您的站点使用 http 而不是 https,则设置为 False

ping_google() 如果无法确定您的站点地图 URL,则会引发异常 django.contrib.sitemaps.SitemapNotFound

先用谷歌注册!

ping_google() 命令仅在您已使用 Google 网站管理员工具 注册您的网站时才有效。


调用 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

然而,更有效的解决方案是从 cron 脚本或其他一些计划任务调用 ping_google()。 该函数向 Google 的服务器发出 HTTP 请求,因此您可能不想在每次调用 save() 时引入该网络开销。

通过 manage.py Ping Google

将站点地图应用程序添加到您的项目后,您还可以使用 ping_google 管理命令 ping Google:

python manage.py ping_google [/sitemap.xml]

如果您的站点地图使用 http 而不是 https,请使用此选项。