指南:无模型视图

SeoViewMixin 适用于任何基于类的视图,包括 TemplateView 以及没有关联模型对象的自定义视图。静态页面用类属性即可;动态页面则重写 get_seo_metadata。


用类属性配置静态页面

# pages/views.py

from django.views.generic import TemplateView
from seo_suite.mixins import SeoViewMixin


class AboutView(SeoViewMixin, TemplateView):
    template_name = "pages/about.html"
    seo_title = "About Us"
    seo_description = "Learn who we are and what we do."
    seo_canonical = "/about/"


class PrivacyPolicyView(SeoViewMixin, TemplateView):
    template_name = "pages/privacy.html"
    seo_title = "Privacy Policy"
    seo_robots = "noindex"

所有 seo_* 类属性都会自动以优先级 50(视图层)被读取。SEO_SUITE["DEFAULTS"] 中的全局默认值仍在其下生效,因此 robots、title_suffix 和 og:type 会直接继承,无需重复写。


根据请求或 URL 参数生成动态标题

标题依赖运行时数据时,重写 get_seo_title:

class SearchResultsView(SeoViewMixin, TemplateView):
    template_name = "search/results.html"

    def get_seo_title(self, context=None):
        query = self.request.GET.get("q", "")
        if query:
            return f'Search results for "{query}"'
        return "Search"

    def get_seo_canonical(self, context=None):
        # Canonical strips the query string; all searches share one canonical.
        return "/search/"

用 get_seo_metadata 完全动态生成元数据

要完全掌控输出,重写 get_seo_metadata 并返回 SeoMetadata.partial(...):

from seo_suite.mixins import SeoViewMixin
from seo_suite.metadata import SeoMetadata
from django.views.generic import TemplateView


class UserDashboardView(SeoViewMixin, TemplateView):
    template_name = "dashboard/index.html"

    def get_seo_metadata(self, context=None):
        user = self.request.user
        return SeoMetadata.partial(
            title=f"{user.first_name}'s Dashboard",
            robots="noindex,nofollow",  # personal pages should not be indexed
        )

SeoMetadata.partial(**kwargs) 只设置你显式指定的字段,其余字段保持 UNSET,由全局默认值补齐。


函数视图

函数视图可以直接调用 resolve_seo,再把结果放进模板上下文:

from seo_suite.context import resolve_seo
from django.shortcuts import render


def contact_view(request):
    seo = resolve_seo(request)
    # Without a view or object, the context processor's lazy resolution is used
    # automatically. You can also construct a SeoMetadata and attach it manually
    # by passing a lightweight wrapper.
    return render(request, "pages/contact.html", {"seo": seo})

也可以完全依赖 seo 上下文处理器。由于该处理器是惰性求值的,任何使用 {% seo_head %} 的模板里都能拿到 seo 变量,函数视图渲染的模板也不例外。区别只在于:不用 mixin 就无法注入视图层的覆盖值。


在模板中使用 h1

解析得到的 h1 字段可在任何模板中通过 {{ seo.h1 }} 访问。它有值时:

<h1>{% if seo.h1 %}{{ seo.h1 }}{% else %}{{ seo.title }}{% endif %}</h1>

由于未设置时 seo.h1 为 None,也可以直接用 default 过滤器:

<h1>{{ seo.h1|default:seo.title }}</h1>