Django integration¶
Call build_seo_payload in your view and pass the result as template context. Use build_seo_payload_dict when you need a plain dict (Django REST Framework, JSON responses).
Function-based view¶
from django.shortcuts import render
from seoslug import SEOConfig, URLPolicy, SEOEntity, build_seo_payload
def post_detail(request, slug):
config = SEOConfig(
canonical_host="blog.example.com",
public_base_url="https://blog.example.com",
url_policy=URLPolicy(),
)
entity = SEOEntity(
entity_type="post",
title="My Post",
excerpt="A short description",
status="published",
)
payload = build_seo_payload(entity, f"/posts/{slug}", config)
return render(request, "post.html", {"payload": payload})
Class-based view¶
from django.views.generic import DetailView
from seoslug import SEOConfig, URLPolicy, SEOEntity, build_seo_payload
class PostDetailView(DetailView):
template_name = "post.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
config = SEOConfig(
canonical_host="blog.example.com",
public_base_url="https://blog.example.com",
url_policy=URLPolicy(),
)
entity = SEOEntity(
entity_type="post",
title=self.object.title,
excerpt=self.object.excerpt,
status="published",
)
context["payload"] = build_seo_payload(entity, self.object.get_absolute_url(), config)
return context
Template context¶
The SEOPayload dataclass supports dict-style access. Use it directly in Django templates.
<head>
<title>{{ payload.title }}</title>
<meta name="description" content="{{ payload.description }}">
<link rel="canonical" href="{{ payload.canonical }}">
<meta name="robots" content="{{ payload.robots }}">
<meta property="og:title" content="{{ payload.og.title }}">
<meta property="og:description" content="{{ payload.og.description }}">
<meta property="og:url" content="{{ payload.og.url }}">
<meta property="og:image" content="{{ payload.og.image }}">
<meta name="twitter:card" content="{{ payload.twitter.card }}">
<meta name="twitter:title" content="{{ payload.twitter.title }}">
<meta name="twitter:description" content="{{ payload.twitter.description }}">
<meta name="twitter:image" content="{{ payload.twitter.image }}">
<script type="application/ld+json">{{ payload.schema_jsonld|safe }}</script>
</head>
You can also call payload.to_dict() and pass the result as context. Both approaches work.
Django REST Framework¶
For DRF views, use build_seo_payload_dict to get a plain dict suitable for JSON serialization.
from rest_framework.decorators import api_view
from rest_framework.response import Response
from seoslug import SEOConfig, URLPolicy, SEOEntity, build_seo_payload_dict
@api_view(["GET"])
def post_detail_api(request, slug):
config = SEOConfig(
canonical_host="blog.example.com",
public_base_url="https://blog.example.com",
url_policy=URLPolicy(),
)
entity = SEOEntity(
entity_type="post",
title="My Post",
excerpt="A short description",
status="published",
)
payload = build_seo_payload_dict(entity, f"/posts/{slug}", config)
return Response({"seo": payload})
Framework caching¶
Use Django's @cache_page decorator with a key prefix derived from the route.
from django.views.decorators.cache import cache_page
@cache_page(60 * 60, key_prefix="seo")
def post_detail(request, slug):
...
For per-URL cache keys, use make_key:
from django.views.decorators.cache import cache_page
def make_seo_key(group, request):
return f"seo:{request.path}"
@cache_page(60 * 60, key_prefix="seo", make_key=make_seo_key)
def post_detail(request, slug):
...
Settings module¶
Define your SEOConfig in settings.py for reuse across all views.
# settings.py
from seoslug import SEOConfig, URLPolicy
SEO_CONFIG = SEOConfig(
canonical_host="blog.example.com",
public_base_url="https://blog.example.com",
url_policy=URLPolicy(allowed_query_params=["page"]),
site_name="My Blog",
default_og_image="https://blog.example.com/default.jpg",
)
# views.py
from django.conf import settings
from seoslug import SEOEntity, build_seo_payload
def post_detail(request, slug):
entity = SEOEntity(entity_type="post", title="My Post", status="published")
payload = build_seo_payload(entity, f"/posts/{slug}", settings.SEO_CONFIG)
return render(request, "post.html", {"payload": payload})