指南:博客文章与文章页面¶
本指南介绍如何为你自己的模型附加 SEO 元数据,从零配置的命名约定,一直到可在后台逐条编辑的字段。
第 1 层:按约定命名字段(无需配置)¶
如果模型已经有名为 title、description(或 summary、excerpt)、image(或 cover_image、photo、thumbnail)的字段,并且实现了 get_absolute_url() 方法,SeoModelMixin 会自动识别它们,无需任何额外配置:
from django.db import models
from seo_suite.mixins import SeoModelMixin
class Article(SeoModelMixin, models.Model):
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
image = models.ImageField(upload_to="articles/", blank=True)
slug = models.SlugField(unique=True)
def get_absolute_url(self):
return f"/articles/{self.slug}/"
完整的约定查找顺序如下:
| SEO 字段 | 依次尝试 |
|---|---|
title |
title、name、headline |
meta_description |
meta_description、description、summary、excerpt |
meta_keywords |
meta_keywords、keywords |
og_image |
og_image、image、cover_image、photo、thumbnail |
canonical_url |
get_absolute_url() 的返回值 |
对于 ImageField 和 FileField 类型的值,只要已上传文件,mixin 会自动调用 .url;字段为空则不提供任何值。
空文本字段("")同样不提供任何值。它与不存在的字段等同处理,因此优先级更低的默认值仍可补上这个空缺。
第 2 层:用 SEO_FIELD_MAP 映射自定义字段名¶
如果模型的字段名与约定不一致,在类属性中声明 SEO_FIELD_MAP:
class Article(SeoModelMixin, models.Model):
headline = models.CharField(max_length=200)
blurb = models.TextField(blank=True)
cover = models.ImageField(upload_to="covers/", blank=True)
slug = models.SlugField(unique=True)
SEO_FIELD_MAP = {
"title": "headline",
"meta_description": "blurb",
"og_image": "cover",
}
def get_absolute_url(self):
return f"/articles/{self.slug}/"
SEO_FIELD_MAP 的值是模型上的属性名。mixin 也接受方法名(无参数的可调用对象会由它代为调用)。
SeoMetadata 的任何字段都可以映射:title、h1、meta_description、meta_keywords、og_image、robots、canonical_url。
第 3 层:逐条可编辑的 SEO 列¶
如果编辑团队需要在不改代码的前提下为单篇文章定制 SEO,使用 SeoModelFieldsMixin。它是一个抽象模型,会直接在你的表中添加 seo_* 列:
from seo_suite.mixins import SeoModelFieldsMixin
class Article(SeoModelFieldsMixin, models.Model):
headline = models.CharField(max_length=200)
blurb = models.TextField(blank=True)
cover = models.ImageField(upload_to="covers/", blank=True)
slug = models.SlugField(unique=True)
SEO_FIELD_MAP = {
"title": "headline",
"meta_description": "blurb",
"og_image": "cover",
}
def get_absolute_url(self):
return f"/articles/{self.slug}/"
SeoModelFieldsMixin 继承自 SeoModelMixin,所以所有命名约定和 SEO_FIELD_MAP 依然有效。在此基础上,它再把自己的列作为更高优先级的一层合并进来:
| 列 | 覆盖 |
|---|---|
seo_title |
title |
seo_description |
meta_description |
seo_keywords |
meta_keywords |
seo_robots |
robots |
seo_canonical |
canonical_url |
seo_og_image |
og_image |
seo_title 列为空表示“不作主张”,此时改用约定回退值(通过 SEO_FIELD_MAP 映射到 headline)。也就是说,编辑只需在想偏离自动值时才填写这些列。
由于 SeoModelFieldsMixin 是抽象模型,迁移需要由你来创建:
在 Django Admin 中注册这些字段¶
# blog/admin.py
from django.contrib import admin
from .models import Article
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
fieldsets = (
(None, {
"fields": ("headline", "blurb", "cover", "slug"),
}),
("SEO", {
"fields": (
"seo_title",
"seo_description",
"seo_keywords",
"seo_robots",
"seo_canonical",
"seo_og_image",
),
"classes": ("collapse",),
"description": (
"Leave blank to use the article's headline and blurb automatically."
),
}),
)
接入详情视图¶
# blog/views.py
from django.views.generic import DetailView
from seo_suite.mixins import SeoViewMixin
from .models import Article
class ArticleDetail(SeoViewMixin, DetailView):
model = Article
slug_field = "slug"
slug_url_kwarg = "slug"
视图会自动把 self.object 传给解析器,你不需要自己调用 get_seo_metadata()。
添加 JSON-LD Article 结构化数据¶
添加 SEO_SCHEMA_PROFILES,即可在 meta 标签之外同时输出一段 Article 结构化数据:
class Article(SeoModelMixin, models.Model):
headline = models.CharField(max_length=200)
blurb = models.TextField(blank=True)
cover = models.ImageField(upload_to="covers/", blank=True)
slug = models.SlugField(unique=True)
published_at = models.DateTimeField()
updated_at = models.DateTimeField(auto_now=True)
author = models.ForeignKey("auth.User", on_delete=models.SET_NULL, null=True)
SEO_FIELD_MAP = {
"title": "headline",
"meta_description": "blurb",
"og_image": "cover",
}
SEO_SCHEMA_PROFILES = ["Article", "BreadcrumbList"]
def get_absolute_url(self):
return f"/articles/{self.slug}/"
def get_breadcrumbs(self):
return [
("Home", "/"),
("Articles", "/articles/"),
(self.headline, self.get_absolute_url()),
]
Article 配置会自动读取 headline、blurb、cover.url、published_at、updated_at 和 author,与上面的字段名一一对应。完整的配置参考见 JSON-LD 结构化数据。
在视图层覆盖特定字段¶
如果要忽略对象本身的值、强制使用某个 SEO 值(例如给草稿内容固定设置一条 robots 指令),使用视图级属性:
视图层(优先级 50)总是优先于对象层(优先级 40)。更多用法见 详情视图。