Django 自带了一个高级站点地图生成框架来创建 sitemap XML 文件。
站点地图是你网站上的一个 XML 文件,它告诉搜索引擎索引器你页面的变化频率,以及某些页面相对于你网站上其他页面的“重要性”。这些信息有助于搜索引擎对你的网站进行索引。
Django 站点地图框架通过让你用 Python 代码表达这些信息以自动创建这个 XML 文件。
它的工作原理很像 Django 的 联合框架。要创建一个站点地图,写一个 Sitemap
类,并将其指向你的 URLconf。
要安装站点地图应用,请按照以下步骤进行:
'django.contrib.sitemaps'
添加到你的 INSTALLED_APPS
配置中。TEMPLATES
配置中包含一个 DjangoTemplates
后端,其 APP_DIRS
选项设置为 True
。默认有一个后端,所以你只需要改变这个配置就可以了。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
类参考¶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
头,防止发送没有变化的站点地图。
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 中允许的上限。
alternates
¶可选的。
一个布尔属性。当与 i18n
结合使用时,生成的 URL 将有一个备用链接列表,使用 hreflang attribute 指向其他语言版本。默认为 False
。
x_default
¶可选的。
一个布尔属性。当 True
时,由 alternates
生成的备用链接将包含一个 hreflang="x-default"
回退条目,其值为 LANGUAGE_CODE
。默认值是 False
。
站点地图框架为常见的情况提供了一个方便的类:
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
字典中定义一个。唯一不同的用法是:
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 文档。
变量 sitemaps
是指向每个站点地图的绝对 URL 的列表。
变量 urlset
是一个应该出现在站点地图中的 URL 列表,每个 URL 都会暴露出 Sitemap
类中定义的属性。
alternates
changefreq
item
lastmod
location
priority
当 i18n
和 alternates
被启用时,alternates
属性可用。它是一个其他语言版本的列表,包括可选的 x_default
回退,对于每个 URL。每个候补是一个字典,有 location
和 lang_code
键。
增加了 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()
时引入网络开销。
12月 07, 2021