Skip to main content

Django app for generating XML sitemaps

Project description

Django Swing Logo

Swing Sitemap

Django Swing Collection

PyPI Python versions License CI Status


Overview

Swing Sitemap is a powerful, CMS-agnostic Django app that extends django.contrib.sitemaps with a settings-driven, drop-in URL helper and versatile sitemap classes. It eliminates the boilerplate of sitemaps.py + urls.py wiring, reducing setup to just a few import lines.

Features

Feature Description
StaticSitemap Sitemap of named Django views with support for view_name, args, kwargs, and lastmod
ModelSitemap Generic queryset adapter for any Django model
VideoSitemap Google Video sitemap with full video metadata support
NewsSitemap Google News sitemap for news articles
ImageSitemap Image sitemap with gallery support
HreflangMixin Multi-language support with hreflang alternate links
Pagination Automatic pagination for large sitemaps (50,000 URLs limit)
Caching Built-in cache support with configurable TTL
Compression Gzip compression for sitemap responses
Signals Auto-invalidate cache on model changes
Search Engine Submission Ping Google, Bing, and custom endpoints
Management Commands CLI tools for generation, validation, and submission

Requirements

  • Python 3.12+
  • Django 5.0+ / 6.0+

Installation

pip install swing-sitemap

Or with Poetry:

poetry add swing-sitemap

Add to INSTALLED_APPS:

INSTALLED_APPS = [
    # ...
    "django.contrib.sitemaps",
    "swing.sitemap",
]

Quick Start

1. Configure Settings

# settings.py
SWING_SITEMAP = {
    # Static pages sitemap
    "static": {
        "views": ["home", "about", "contact"],
        "priority": 0.6,
        "changefreq": "weekly",
    },
    # Model-based sitemaps
    "models": {
        "blog": {
            "model": "blog.Post",
            "filters": {"is_published": True},
            "order_by": ["-published_at"],
            "date_field": "updated_at",
            "priority": 0.8,
            "changefreq": "daily",
        },
        "products": {
            "model": "shop.Product",
            "filters": {"active": True},
            "priority": 0.7,
        },
    },
    # Caching (optional)
    "cache": {
        "enabled": True,
        "timeout": 3600,  # 1 hour
        "key_prefix": "sitemap",
    },
    # Pagination (optional)
    "pagination": {
        "enabled": True,
        "items_per_page": 10000,
    },
}

2. Wire URLs

# urls.py
from swing.sitemap.urls import sitemap_urlpatterns

urlpatterns = [
    # ... your views ...
    *sitemap_urlpatterns(),
]

That's it! Your sitemap is now available at /sitemap.xml.

3. Add to robots.txt (Optional)

# settings.py
TEMPLATES = [
    {
        # ...
        "OPTIONS": {
            "context_processors": [
                # ...
                "swing.sitemap.context_processors.sitemap_url",
            ],
        },
    },
]
# templates/robots.txt
Sitemap: {{ sitemap_url }}

Or use the template tag:

{% load swing_sitemap %}
Sitemap: {% sitemap_url %}

Sitemap Classes

StaticSitemap

For named Django views:

from swing.sitemap import StaticSitemap

sitemap = StaticSitemap(
    views=["home", "about", {"view_name": "blog:archive", "kwargs": {"year": 2024}}],
    priority=0.8,
    changefreq="weekly",
)

ModelSitemap

For Django model querysets:

from swing.sitemap import ModelSitemap
from blog.models import Post

sitemap = ModelSitemap(
    queryset=Post.objects.filter(is_published=True),
    date_field="updated_at",
    priority=0.7,
)

VideoSitemap

For video content (Google Video Sitemaps):

from swing.sitemap import VideoSitemap

class MyVideoSitemap(VideoSitemap):
    def items(self):
        return Video.objects.filter(published=True)

    def video_title(self, obj):
        return obj.title

    def video_description(self, obj):
        return obj.description

    def video_thumbnail_loc(self, obj):
        return obj.thumbnail.url

NewsSitemap

For news articles (Google News Sitemaps):

from swing.sitemap import NewsSitemap

class MyNewsSitemap(NewsSitemap):
    publication_name = "My News Site"
    publication_language = "en"

    def items(self):
        return Article.objects.filter(
            published_at__gte=timezone.now() - timedelta(days=2)
        )

HreflangMixin

For multi-language sites:

from swing.sitemap import ModelSitemap, HreflangMixin

class I18nBlogSitemap(HreflangMixin, ModelSitemap):
    languages = ["en", "de", "fr"]

    def alternates(self, obj):
        return {
            lang: f"/{lang}/blog/{obj.slug}/"
            for lang in self.languages
        }

Management Commands

Generate Static Sitemap

python manage.py generate_sitemap --output sitemap.xml

Validate Sitemap

# Validate from URL
python manage.py validate_sitemap https://example.com/sitemap.xml

# Validate all configured sitemaps
python manage.py validate_sitemap --all

Submit to Search Engines

python manage.py submit_sitemap https://example.com/sitemap.xml

Clear Sitemap Cache

python manage.py clear_sitemap_cache

Celery Tasks (Optional)

For async sitemap submission:

# settings.py
SWING_SITEMAP = {
    "submit": {
        "sitemap_url": "https://example.com/sitemap.xml",
        "endpoints": {
            "google": "https://www.google.com/ping?sitemap={url}",
            "bing": "https://www.bing.com/ping?sitemap={url}",
        },
    },
}
# tasks.py
from swing.sitemap.tasks import submit_sitemap_task

# Submit immediately
submit_sitemap_task.delay()

Composing Extra Sitemaps

Swing Sitemap is CMS-agnostic. Integrate with Wagtail or other CMSes:

from swing.sitemap import default_sitemaps, sitemap_urlpatterns
from wagtail.contrib.sitemaps import Sitemap as WagtailSitemap

sitemaps = {**default_sitemaps(), "wagtail": WagtailSitemap}

urlpatterns = [
    *sitemap_urlpatterns(sitemaps=sitemaps),
]

Configuration Reference

Setting Type Default Description
static.views list [] List of view names or dicts
static.priority float 0.5 Default priority for static URLs
static.changefreq str "monthly" Default change frequency
models.<key>.model str Required Model path (e.g., "app.Model")
models.<key>.filters dict {} Queryset filter kwargs
models.<key>.order_by list [] Ordering fields
models.<key>.date_field str None Field for lastmod
models.<key>.priority float 0.5 URL priority (0.0-1.0)
models.<key>.changefreq str "monthly" Change frequency
cache.enabled bool False Enable sitemap caching
cache.timeout int 3600 Cache TTL in seconds
cache.key_prefix str "swing_sitemap" Cache key prefix
pagination.enabled bool False Enable pagination
pagination.items_per_page int 50000 URLs per sitemap page
compression.enabled bool False Enable gzip compression

Signals

Automatically invalidate cache when models change:

# apps.py
from django.apps import AppConfig

class BlogConfig(AppConfig):
    def ready(self):
        from swing.sitemap import register_sitemap_signals
        from .models import Post

        register_sitemap_signals(Post)

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

# Clone the repository
git clone https://github.com/swing-collection/swing-sitemap.git
cd swing-sitemap

# Install dependencies
poetry install

# Run tests
poetry run pytest

# Run linters
poetry run flake8 src/
poetry run pylint src/

License

This project is licensed under the BSD-3-Clause License. See LICENSE for details.

Links

robots.txt

Use the template tag or context processor:

{% load swing_sitemap %}
Sitemap: {% sitemap_url %}

Or enable the context processor and reference {{ SITEMAP_URL }}:

TEMPLATES = [{
    "OPTIONS": {
        "context_processors": [
            # ...
            "swing_sitemap.context_processors.sitemap_url",
        ],
    },
}]

Settings reference

Key Default Notes
static.views [] List of URL names or {view_name, args, kwargs, lastmod} dicts.
static.priority 0.5 Default <priority> for every static entry.
static.changefreq "monthly" Default <changefreq> for every static entry.
models.<key>.model required Dotted "app.Model".
models.<key>.filters {} **filters passed to qs.filter().
models.<key>.exclude {} **filters passed to qs.exclude().
models.<key>.order_by [] Args passed to qs.order_by().
models.<key>.date_field None Attribute used for <lastmod>.
models.<key>.location_attr "get_absolute_url" Attribute or zero-arg callable returning the URL.
models.<key>.priority None Per-sitemap <priority>.
models.<key>.changefreq None Per-sitemap <changefreq>.
priority / changefreq {} Free-form per-key dicts (legacy SEO_SITEMAP_* shims fold in here).

Backward-compatibility shims

The following legacy settings still work but emit a DeprecationWarning the first time get_config() runs:

  • SEO_SITEMAP_PRIORITYSWING_SITEMAP["priority"]
  • SEO_SITEMAP_CHANGEFREQSWING_SITEMAP["changefreq"]
  • VIDEO_SITEMAP_MODELSWING_SITEMAP["video"]["model"]

Testing

poetry install --with dev
poetry run pytest

Colophon

Made with ❤️ by Scape Press

Contributing

Contributions are welcome! Please fork the repository and submit a pull request with your changes.

License

This project is licensed under the BSD-3-Clause license. See the LICENSE file for details.


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

swing_sitemap-0.1.2.tar.gz (55.2 kB view details)

Uploaded Source

Built Distribution

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

swing_sitemap-0.1.2-py3-none-any.whl (103.9 kB view details)

Uploaded Python 3

File details

Details for the file swing_sitemap-0.1.2.tar.gz.

File metadata

  • Download URL: swing_sitemap-0.1.2.tar.gz
  • Upload date:
  • Size: 55.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for swing_sitemap-0.1.2.tar.gz
Algorithm Hash digest
SHA256 aff60922187ec980dafce1f2b8f822dfcc62a28871cb639c32095e4d8265907f
MD5 238c396be21301f5443c0f39c8961a69
BLAKE2b-256 b878ed3b6c52cdcdffce0b31d49d60806346eb52427bd9c2b278fb48ab12500c

See more details on using hashes here.

File details

Details for the file swing_sitemap-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: swing_sitemap-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 103.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for swing_sitemap-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0092d67cc2789907b21fb1b4575a754bd4e31b95b997cb97f5c17e29d5a0f6e1
MD5 e790ea5ad76c78a9b8145edf6a5f5b6a
BLAKE2b-256 d3676104cf74ff31b0b6a2d400f5689159db99159a591a57ca0596e8aaf064f6

See more details on using hashes here.

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