站点地图框架

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 应该是一个字典,它将一个简短的章节标签(例如,blognews)映射到它的 Sitemap 类(例如,BlogSitemapNewsSitemap)。也可以映射到一个 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

注意:

  • changefreqpriority 分别是用作 <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[source]

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

items()[source]

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[source]

可选的。 方法或属性。

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[source]

可选的。

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.41.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

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

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 条目,用于指定从 queryset 中检索的对象的日期字段。这将在生成的站点地图中用于 lastmod 属性和 get_latest_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},
        name="django.contrib.sitemaps.views.index",
    ),
    path(
        "sitemap-<section>.xml",
        views.sitemap,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

这将自动生成一个 sitemap.xml 文件,同时引用 sitemap-flatpages.xmlsitemap-blog.xmlSitemap 类和 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 向 sitemapindex 视图传递一个 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 是一个包含每个站点地图的 locationlastmod 属性的对象列表。每个 URL 具有以下属性:

  • location:站点地图的位置(URL 和页面)。

  • lastmod:由每个站点地图的 get_latest_lastmod() 方法填充。

Sitemap

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

  • alternates

  • changefreq

  • item

  • lastmod

  • location

  • priority

i18nalternates 被启用时,alternates 属性可用。它是一个其他语言版本的列表,包括可选的 x_default 回退,对于每个 URL。每个候补是一个字典,有 locationlang_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>