指南:站点地图

SeoSitemap 是 Django django.contrib.sitemaps.Sitemap 的一个轻量子类。它的关键特性是:每个条目的 <loc> URL 取自该条目解析出的 SEO 规范地址(canonical),因此站点地图中的 URL 始终与页面上的 rel="canonical" 保持一致。这样就从根上避免了一个常见又难以察觉的 SEO 问题:站点地图 URL 与 canonical 标签不一致。


基础站点地图

# sitemaps.py
from seo_suite.sitemaps import SeoSitemap
from .models import Article


class ArticleSitemap(SeoSitemap):
    changefreq = "weekly"
    priority = 0.8

    def items(self):
        return Article.objects.filter(published=True)
# urls.py
from django.contrib.sitemaps.views import sitemap
from .sitemaps import ArticleSitemap

sitemaps = {"articles": ArticleSitemap}

urlpatterns = [
    path("sitemap.xml", sitemap, {"sitemaps": sitemaps}),
]

自动生成 lastmod

SeoSitemap 会按以下顺序检查每个条目上的属性,并把第一个找到的属性值作为 <lastmod>:

updated_at → modified → date_modified → updated → last_modified

如果这些属性都不存在,则省略 <lastmod>。常见的带有 updated_at = DateTimeField(auto_now=True) 字段的模型无需额外配置即可直接使用。


带 hreflang 替代链接的多语言站点地图

把 Django 内置的站点地图 i18n 属性与 SeoSitemap 结合使用:

class ArticleSitemap(SeoSitemap):
    i18n = True
    alternates = True
    x_default = True
    changefreq = "weekly"

    def items(self):
        return Article.objects.filter(published=True)

设置 i18n = True 后,Django 会为每个条目、每种启用的语言各生成一个 <url>。alternates = True 会为每种语言添加 <xhtml:link rel="alternate"> 条目,x_default = True 则额外添加 x-default 替代链接。

由于每个 <loc> 都来自对象的 get_seo_metadata().canonical_url(经由 SeoSitemap.location()),站点地图中的规范 URL 始终与页面上渲染出的规范 URL 保持同步。


SeoSitemap.location 的工作原理

对于使用了 SeoModelMixin 的条目,location() 会调用 get_seo_metadata() 并取出其中的 canonical_url。这里只使用路径和查询字符串部分,协议和主机名由 Django 的站点地图框架根据当前的 Site 对象补全。

如果条目没有 get_seo_metadata(),或者 canonical_url 未设置,location() 会回退到 Django 的默认行为,即调用 item.get_absolute_url()。


多个站点地图

在 urls.py 中组合多个站点地图:

from django.contrib.sitemaps.views import sitemap
from .sitemaps import ArticleSitemap, CategorySitemap, PageSitemap

sitemaps = {
    "articles": ArticleSitemap,
    "categories": CategorySitemap,
    "pages": PageSitemap,
}

urlpatterns = [
    path("sitemap.xml", sitemap, {"sitemaps": sitemaps}),
]

站点地图索引

对于大型站点,可以使用 Django 的 SitemapIndexSite,或者按常规方式拆分成多个站点地图即可。SeoSitemap 对条目数量没有限制。


把静态页面加入站点地图

对于没有对应模型的页面,写一个直接返回路径的简单站点地图即可:

from django.contrib.sitemaps import Sitemap


class StaticViewSitemap(Sitemap):
    priority = 0.5

    def items(self):
        return ["/about/", "/contact/", "/privacy/"]

    def location(self, item):
        return item

只有当条目具有 get_seo_metadata() 时才需要 SeoSitemap。对于纯静态路径,Django 内置的 Sitemap 就足够了。


在 robots.txt 中指向站点地图

站点地图 URL 稳定下来之后,把它加入 ROBOTS_SITEMAP_URLS,爬虫就能始终通过 robots.txt 找到它:

SEO_SUITE = {
    "ROBOTS_SITEMAP_URLS": ["https://example.com/sitemap.xml"],
}

该 URL 会以 Sitemap: 指令的形式追加到每次返回的 robots.txt 末尾,你无需修改任何版本内容。完整流程见 robots.txt 版本管理指南。