站点地图框架

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() 方法返回一个对象序列或 QuerySet。这些对象会传递给与站点地图属性对应的可调用方法,包括 location、lastmod、changefreq 和 priority。

  • lastmod 应该返回一个 datetime。

  • 本例没有定义 location 方法,但你可以提供这个方法来指定对象的 URL。默认情况下,location 会调用每个对象的 get_absolute_url() 并返回其结果。

Sitemap 类参考

class Sitemap[source]

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

items()[source]

必需。这是一个返回对象序列或 QuerySet 的方法。框架不关心对象的具体类型;重要的是,这些对象会传递给 location、lastmod、changefreq 和 priority 方法。

location[source]

可选的。 方法或属性。

如果定义为方法,它应当返回 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[source]

可选的。

这个属性返回 items() 对应的 Paginator。如果批量生成站点地图,可以考虑将其重写为缓存属性,以避免重复调用 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')。如果未设置,则使用请求站点地图时使用的协议。如果站点地图是在没有请求上下文的情况下构建的,默认值为 '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()[source]

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

默认情况下,get_latest_lastmod() 返回:

  • 如果 lastmod 是一个属性:lastmod。

  • 如果 lastmod 是方法:对 items() 返回的所有对象调用该方法,并返回其中最新的 lastmod。

get_languages_for_item(item)[source]

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

捷径

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

class GenericSitemap(info_dict, priority=None, changefreq=None, protocol=None)[source]

django.contrib.sitemaps.GenericSitemap 类允许通过字典创建站点地图。该字典至少需要包含 queryset 项,用于生成站点地图中的条目。还可以包含 date_field 项,指定查询集对象上的日期字段;生成站点地图时,这个字段用于 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 行的样子:

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 字典完全没有变化。

如果所有站点地图都能通过 get_latest_lastmod() 返回 lastmod,站点地图索引就会带有 Last-Modified 响应头,其值为最新的 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 键。

每个 URL 都添加了 item 属性,便于更灵活地自定义模板,例如生成 Google 新闻站点地图。假定 Sitemap 的 items() 返回的条目包含 publication_data 和 tags 字段,下面这样的代码就能生成兼容 Google 新闻的站点地图:

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

原文:站点地图框架。作者/来源:Django 项目与文档贡献者。本文依据所列原文整理为中文,代码、命令与配置示例保留原文。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容