Quickstart — your first SEO-enabled model¶
This guide takes an existing Django blog Article model and adds full SEO
metadata in three steps. You should have completed Installation
first.
Step 1: Add SeoModelMixin to your model¶
# blog/models.py
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)
slug = models.SlugField(unique=True)
published = models.BooleanField(default=False)
def get_absolute_url(self):
return f"/articles/{self.slug}/"
That is the only change to the model. No new columns, no migration.
SeoModelMixin reads metadata from the model's existing fields using
conventional field names:
| Metadata field | Fields tried, in order |
|---|---|
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 |
return value of get_absolute_url() |
If your fields have different names, use SEO_FIELD_MAP to tell the mixin
where to look. See Blog posts and articles for details.
Step 2: Add SeoViewMixin to your detail view¶
# 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
template_name = "blog/article_detail.html"
slug_field = "slug"
slug_url_kwarg = "slug"
SeoViewMixin wires the view's context object (self.object) into the
resolver. The object's get_seo_metadata() is called automatically; the
resulting FinalizedSeoMetadata is placed in the template context as seo.
Step 3: Add {% seo_head %} to your base template¶
If you already added {% seo_head %} to your base template during installation,
nothing more is needed. If you are using a per-page template:
{# blog/templates/blog/article_detail.html #}
{% extends "base.html" %}
{% load seo_suite %}
{% block extra_head %}
{% seo_head %}
{% endblock %}
Or, in a base template that all pages share:
{# templates/base.html #}
{% load seo_suite %}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{% seo_head %}
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
What gets rendered¶
Given an Article with title="How Django Routing Works",
description="A deep dive into URL resolvers.", and
slug="how-django-routing-works", and a site running at https://example.com,
the <head> block renders:
<title>How Django Routing Works</title>
<meta name="description" content="A deep dive into URL resolvers.">
<meta name="robots" content="index,follow">
<link rel="canonical" href="https://example.com/articles/how-django-routing-works/">
<meta property="og:type" content="website">
<meta property="og:title" content="How Django Routing Works">
<meta property="og:description" content="A deep dive into URL resolvers.">
<meta property="og:url" content="https://example.com/articles/how-django-routing-works/">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="How Django Routing Works">
<meta name="twitter:description" content="A deep dive into URL resolvers.">
A few things to note:
og:titleandog:descriptionare populated from the page title and description, with no extra code needed.og:urlmirrors the canonical URL.twitter:carddefaults to"summary"when there is no image, and becomes"summary_large_image"when an image is present.robots: index,followcomes from the global default inSEO_SUITE["DEFAULTS"]. You can change it per-page or site-wide; see Site-wide defaults.
Adding a title suffix¶
A site-wide suffix like " | My Blog" is a single settings entry:
# settings.py
SEO_SUITE = {
"DEFAULTS": {
"title_suffix": " | My Blog",
"robots": "index,follow",
},
}
The <title> tag now renders as:
Next steps¶
- Add per-row, editor-editable SEO fields: Blog posts and articles
- Add list page SEO: Listing pages
- Add JSON-LD Article schema: JSON-LD structured data
- Understand the full resolution order: How resolution works