Skip to main content

Protocol-based SEO auditing framework for Django models with automatic rule discovery

Project description

Django SEO Audit

A production-ready Django package for comprehensive SEO auditing of models using Python protocols and automatic rule discovery.

Features

  • Protocol-Based Architecture: Uses Python 3.12+ protocols for clean, loosely-coupled design
  • Automatic Rule Discovery: Rules auto-register when defined - no manual registration needed
  • Auto-Discovery Management Command: Automatically finds and audits any model using SEOAuditableMixin
  • Comprehensive Rule Set: 18 built-in rules across 4 categories:
    • Core SEO: Title length, meta descriptions, keywords, H1 tags
    • Social Media: OpenGraph and Twitter Card optimization
    • Content Quality: Content depth, introduction, resources
    • Technical SEO: Canonical URLs, robots directives, structured data
  • Django Model Mixin: Drop-in mixin with intelligent fallbacks for common field names
  • Extensible: Easy to add custom rules for your specific SEO requirements
  • Beautiful CLI Output: Color-coded results with emoji indicators and actionable suggestions

Installation

From PyPI (when published)

pip install django-seo-audit

From Source (Development)

# In your workspace directory
git clone https://github.com/directory-platform/django-seo-audit.git
cd django-seo-audit
pip install -e .

UV Workspace (Recommended for development)

Add to your workspace pyproject.toml:

[tool.uv.workspace]
members = [
    "your-project",
    "django-seo-audit",
]

Then run:

uv sync

Quick Start

1. Add to Django Settings

# settings.py
INSTALLED_APPS = [
    # ...
    "django_seo_audit",
]

2. Add Mixin to Your Models

# models.py
from django.db import models
from django_seo_audit import SEOAuditableMixin

class Article(SEOAuditableMixin, models.Model):
    name = models.CharField(max_length=200)
    seo_title = models.CharField(max_length=60, blank=True)
    meta_description = models.TextField(max_length=160, blank=True)
    focus_keyphrase = models.CharField(max_length=100, blank=True)

    # ... other fields

The mixin provides intelligent fallbacks:

  • get_seo_title()seo_title or name
  • get_meta_description()meta_description or short_description
  • get_h1_tag()h1_tag or seo_title or name

3. Run SEO Audit

# List all auditable models
python manage.py seo_audit --list-models

# Audit a specific object
python manage.py seo_audit --model blog.Article --slug my-article

# Audit with verbose output and specific categories
python manage.py seo_audit --model blog.Article --slug my-article --verbose --category core_seo

4. Programmatic Usage

from django_seo_audit import SEOAuditor

# Audit any object
article = Article.objects.get(slug="my-article")
auditor = SEOAuditor()
result = auditor.audit_object(article)

# Check results
print(f"SEO Score: {result.overall_score}/10")
print(f"Grade: {result.get_health_grade()}")
print(f"Passing: {result.is_passing()}")

# Get issues by severity
critical_issues = result.get_critical_issues()
warnings = result.get_warnings()
successes = result.get_successes()

Protocols

Django SEO Audit uses Python protocols to define contracts for auditable objects. Your models don't need to inherit from anything - just implement the methods you need.

BasicSEOAuditable

Core SEO methods every model should implement:

from django_seo_audit import BasicSEOAuditable

def get_seo_title(self) -> str: ...
def get_meta_description(self) -> str: ...
def get_canonical_url(self) -> str: ...
def get_focus_keyphrase(self) -> str: ...
def get_secondary_keywords(self) -> str: ...
def get_h1_tag(self) -> str: ...

SocialMediaAuditable

For social sharing optimization:

from django_seo_audit import SocialMediaAuditable

def get_og_title(self) -> str: ...
def get_og_description(self) -> str: ...
def get_og_image_url(self) -> str | None: ...
def get_twitter_title(self) -> str: ...
def get_twitter_description(self) -> str: ...
def get_twitter_image_url(self) -> str | None: ...

ContentAuditable

For content quality assessment:

from django_seo_audit import ContentAuditable

def has_detailed_content(self) -> bool: ...
def get_content_word_count(self) -> int: ...
def get_content_sections_count(self) -> int: ...
def has_introduction_content(self) -> bool: ...
def get_resource_count(self) -> int: ...

TechnicalSEOAuditable

For technical SEO features:

from django_seo_audit import TechnicalSEOAuditable

def get_robots_directive(self) -> str: ...
def get_schema_type(self) -> str: ...
def get_schema_data(self) -> dict | None: ...
def get_breadcrumb_title(self) -> str: ...
def has_custom_canonical_url(self) -> bool: ...

Creating Custom Rules

Creating custom SEO rules is straightforward:

# rules/custom_rules.py
from django_seo_audit import SEORule, SEOResult, SEOStatus
from django_seo_audit.protocols import BasicSEOAuditable

class CustomKeywordDensityRule(SEORule):
    """Check keyword density in content."""

    name = "Keyword Density"
    description = "Ensures focus keyword appears with optimal density"
    category = "custom"
    weight = 3  # 1-5 importance scale

    def check(self, obj: BasicSEOAuditable) -> SEOResult:
        keyword = obj.get_focus_keyphrase()
        # Your logic here

        return SEOResult(
            status=SEOStatus.GOOD,
            message="Keyword density optimal",
            score=10,
        )

Rules are automatically discovered and registered when imported!

Management Command Reference

List Auditable Models

python manage.py seo_audit --list-models

Shows all models using SEOAuditableMixin with object counts.

Audit by Slug

python manage.py seo_audit --model app_label.ModelName --slug object-slug

Audit by Primary Key

python manage.py seo_audit --model app_label.ModelName --pk 42

Filter by Category

python manage.py seo_audit --model blog.Article --slug test \
    --category core_seo \
    --category social_media

Available categories: core_seo, social_media, content, technical_seo

Verbose Output

python manage.py seo_audit --model blog.Article --slug test --verbose

Shows detailed explanations and actionable suggestions for improvements.

Built-in Rules

Core SEO (5 rules)

  • SEO Title Length: Optimal 50-60 characters
  • Meta Description Length: Optimal 150-160 characters
  • Focus Keyphrase: Presence in title and description
  • H1 Tag Optimization: Proper H1 configuration
  • Secondary Keywords: 3-7 keyword variety

Social Media (5 rules)

  • OpenGraph Image: 1200x630px image configuration
  • OpenGraph Title: Up to 95 characters
  • OpenGraph Description: Up to 200 characters
  • Twitter Card Image: Twitter-optimized imagery
  • Twitter Card Title: Up to 70 characters

Content (4 rules)

  • Detailed Content: Comprehensive content sections
  • Introduction Content: Engaging introduction
  • Supporting Resources: Videos, articles, tools
  • Content Depth: 500+ words across sections

Technical SEO (4 rules)

  • Canonical URL: Duplicate content prevention
  • Robots Directive: Proper indexing configuration
  • Structured Data: Schema.org markup
  • Breadcrumb Optimization: Navigation clarity

Architecture

  • Protocol-Based: Uses Python 3.12+ Protocol for structural subtyping
  • Auto-Registration: Rules register via __init_subclass__ metaclass magic
  • Immutable Results: SEOResult uses frozen dataclass for thread-safety
  • Graceful Degradation: Failed rules don't break the entire audit
  • Zero Config: Works out of the box with sensible defaults

Requirements

  • Python 3.12+
  • Django 4.2+

Development

# Clone repository
git clone https://github.com/heysamtexas/django-seo-audit.git
cd django-seo-audit

# Install with dev dependencies
pip install -e ".[dev]"

# Run linting
ruff check .
ruff format .

# Type checking
mypy src/

Releases and Publishing

This package uses GitHub Actions to automatically publish to PyPI when a new release is created.

Creating a Release

  1. Update version in pyproject.toml:

    [project]
    version = "0.1.1"  # Bump version
    
  2. Commit version bump:

    git add pyproject.toml
    git commit -m "Bump version to 0.1.1"
    git push origin master
    
  3. Create GitHub release:

    # Using GitHub CLI
    gh release create v0.1.1 --title "Release v0.1.1" --notes "Release notes here"
    
    # Or use GitHub web interface
    # Navigate to: https://github.com/heysamtexas/django-seo-audit/releases/new
    
  4. GitHub Actions will automatically:

    • Verify version matches tag
    • Run tests
    • Build package
    • Publish to PyPI

PyPI Trusted Publisher Setup (First Release Only)

Before creating your first release, configure PyPI Trusted Publisher:

  1. Go to PyPI: https://pypi.org/manage/account/publishing/

  2. Add a new pending publisher:

    • PyPI Project Name: django-seo-audit
    • Owner: heysamtexas
    • Repository name: django-seo-audit
    • Workflow name: publish.yml
    • Environment name: (leave blank)
  3. Create first release - PyPI will create the project automatically

No API tokens needed! Trusted Publishers are more secure and maintenance-free.

Contributing

Contributions welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-rule)
  3. Commit your changes (git commit -m 'Add amazing SEO rule')
  4. Push to the branch (git push origin feature/amazing-rule)
  5. Open a Pull Request

License

MIT License - see LICENSE file for details.

Credits

Built by the Directory Platform team as part of the directory ecosystem.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_seo_audit-0.1.0.tar.gz (24.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_seo_audit-0.1.0-py3-none-any.whl (26.4 kB view details)

Uploaded Python 3

File details

Details for the file django_seo_audit-0.1.0.tar.gz.

File metadata

  • Download URL: django_seo_audit-0.1.0.tar.gz
  • Upload date:
  • Size: 24.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_seo_audit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8ef07e8f571e9c8ad767c85d5f721a5691608ff572ca5bd2ccb7c2dc5cd54eee
MD5 56e9dfdd7cc3bb5aa1bb28df76175e1e
BLAKE2b-256 18ecd22c14fbca36951fd60f5afbf98c9a6f5a8fd9e59f00128c1a49b22f7019

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_seo_audit-0.1.0.tar.gz:

Publisher: publish.yml on heysamtexas/django-seo-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_seo_audit-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_seo_audit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 494b4358dff44c7845fc99c032214dd229e92f25fb66d7f983ec99a74ad1213d
MD5 b78af659456c8ecc93af14de20fdec0b
BLAKE2b-256 e163f34483160cd695f6f0f9e5f5036fa9fa499478d3f556d7dd09f1f4a3676c

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_seo_audit-0.1.0-py3-none-any.whl:

Publisher: publish.yml on heysamtexas/django-seo-audit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page