サイトマップ・フレームワーク

Djangoには、 sitemap XML ファイルを作成するための高レベルなサイトマップ生成フレームワークが付属しています。

概要

サイトマップとは、検索エンジンのインデクサーに、ページの変更頻度や、あるページがサイト内の他のページと比較してどの程度「重要」であるかを伝える、ウェブサイト上のXMLファイルのことです。この情報は、検索エンジンがあなたのサイトをインデックスするのに役立ちます。

Django サイトマップフレームワークは、この情報を Python コードで表現することで、XML ファイルの作成を自動化します。

これは Django の 配信 (syndication) フレームワーク のように動作します。サイトマップを作成するには、 Sitemap クラスを書き、 URLconf の中でそれを指定します。

インストール

サイトマップ アプリをインストールするには、以下の手順に従ってください。

  1. 'django.contrib.sitemaps' を INSTALLED_APPS 設定に追加します。

  2. TEMPLATES 設定には、DjangoTemplates バックエンドが含まれており、APP_DIRS オプションが True に設定されていることを確認してください。これはデフォルトで設定されているので、設定を変更していない場合は、この設定を変更する必要はありません。

  3. sites フレームワーク がインストールされていることを確認してください。

(注意: サイトマップアプリケーションはデータベーステーブルをインストールしません。 INSTALLED_APPS に入れる必要があるのは、 Loader() テンプレートローダーがデフォルトのテンプレートを見つけられるようにするためです)。

初期設定

views.sitemap(request, sitemaps, section=None, template_name='sitemap.xml', content_type='application/xml')

Django サイトでサイトマップの生成を有効にするには、 URLconf に以下の行を追加します:

from django.contrib.sitemaps.views import sitemap

path(
    "sitemap.xml",
    sitemap,
    {"sitemaps": sitemaps},
    name="django.contrib.sitemaps.views.sitemap",
)

これは Django に、クライアントが /sitemap.xml にアクセスしたときにサイトマップを構築するように指示します。

サイトマップファイルの名前は重要ではありませんが、場所は重要です。検索エンジンは、現在のURLレベル以下のサイトマップのリンクだけをインデックスします。例えば、 sitemap.xml がルートディレクトリにある場合、サイト内のどのURLでも参照できます。しかし、サイトマップが /content/sitemap.xml にある場合は、 /content/ で始まるURLのみを参照できます。

サイトマップビューは追加の必須引数を取ります: {'sitemaps': sitemaps}. sitemaps は短いセクションラベル (例えば blog や news) を Sitemap クラス (例えば BlogSitemap や NewsSitemap) にマップする辞書です。また、 Sitemap クラスの インスタンス (例えば BlogSitemap(some_var)) にマップすることもできます。

Sitemap クラス

Sitemap クラスは、サイトマップ内のエントリの「セクション」を表す Python クラスです。例えば、1 つの Sitemap クラスはブログのすべてのエントリを表し、別のクラスはイベントカレンダー内のすべてのイベントを表すことができます。

最も単純なケースでは、これらのセクションはすべて1つの sitemap.xml にまとめられますが、フレームワークを使って、セクションごとに1つのサイトマップファイルを参照するサイトマップインデックスを生成することもできます。(下記の Creating a sitemap index を参照してください)。

Sitemap クラスは django.contrib.sitemaps.Sitemap のサブクラスでなければなりません。これらはコードベースのどこにあっても構いません。

例

たとえば、 Entry モデルのブログシステムがあり、サイトマップに個々のブログエントリへのリンクをすべて含めたいとします。サイトマップクラスは次のようになります:

from django.contrib.sitemaps import Sitemap
from blog.models import Entry


class BlogSitemap(Sitemap):
    changefreq = "never"
    priority = 0.5

    def items(self):
        return Entry.objects.filter(is_draft=False)

    def lastmod(self, obj):
        return obj.pub_date

備考:

  • changefreq と priority はそれぞれ <changefreq> と <priority> 要素に対応するクラス属性です。これらは例の lastmod のように関数として呼び出すことができます。

  • items() is a method that returns a sequence or QuerySet of objects. The objects returned will get passed to any callable methods corresponding to a sitemap property (location, lastmod, changefreq, and priority).

  • lastmod は datetime を返すべきです。

  • There is no location method in this example, but you can provide it in order to specify the URL for your object. By default, location calls get_absolute_url() on each object and returns the result.

Sitemap クラス リファレンス

class Sitemap[ソース]

サイトマップ Sitemap クラスは以下のメソッドや属性を定義できます:

items()[ソース]

Required. A method that returns a sequence or QuerySet of objects. The framework doesn't care what type of objects they are; all that matters is that these objects get passed to the location, lastmod, changefreq and priority methods.

location[ソース]

オプション。 メソッドまたは属性のいずれか。

If it's a method, it should return the absolute path for a given object as returned by items().

If it's an attribute, its value should be a string representing an absolute path to use for every object returned by items().

どちらの場合も、「絶対パス」とは、プロトコルやドメインを含まないURLを意味します。たとえば:

  • 良い例: '/foo/bar/'

  • 悪い例: 'example.com/foo/bar/'

  • 悪い例: 'https://example.com/foo/bar/'

If location isn't provided, the framework will call the get_absolute_url() method on each object as returned by items.

'http' 以外のプロトコルを指定するには、 protocol を使用してください。

lastmod

オプション。 メソッドまたは属性のいずれか。

If it's a method, it should take one argument -- an object as returned by items() -- and return that object's last-modified date/time as a datetime.

If it's an attribute, its value should be a datetime representing the last-modified date/time for every object returned by items().

サイトマップ内のすべてのアイテムに lastmod がある場合、 views.sitemap() によって生成されるサイトマップには、最新の lastmod に等しい Last-Modified ヘッダーが付きます。リクエストに If-Modified-Since ヘッダーがある場合、Django が適切に応答するようにするには、 ConditionalGetMiddleware をアクティブにします。これにより、サイトマップが変更されていない場合には送信を防ぎます。

paginator[ソース]

オプション。

This property returns a Paginator for items(). If you generate sitemaps in a batch you may want to override this as a cached property in order to avoid multiple items() calls.

changefreq

オプション。 メソッドまたは属性のいずれか。

If it's a method, it should take one argument -- an object as returned by items() -- and return that object's change frequency as a string.

If it's an attribute, its value should be a string representing the change frequency of every object returned by items().

changefreq の可能な値は、メソッドの場合も属性の場合も、以下の通りです。

  • 'always'

  • 'hourly'

  • 'daily'

  • 'weekly'

  • 'monthly'

  • 'yearly'

  • 'never'

priority

オプション。 メソッドまたは属性のいずれか。

If it's a method, it should take one argument -- an object as returned by items() -- and return that object's priority as either a string or float.

If it's an attribute, its value should be either a string or float representing the priority of every object returned by items().

priority の例として、0.4、1.0 を指定します。ページのデフォルトの優先度は 0.5 です。詳細については、sitemaps.org documentation を参照してください。

protocol

オプション。

この属性はサイトマップのURLのプロトコル ('http' または 'https') を定義します。設定されていない場合は、サイトマップがリクエストされたプロトコルが使用されます。サイトマップがリクエストのコンテキスト外で作成された場合、デフォルトは 'https' です。

limit

オプション。

この属性はサイトマップの各ページに含まれるURLの最大数を定義します。この値はデフォルト値の 50000 を超えてはいけません。これは Sitemaps protocol で許可されている上限値です。

i18n

オプション。

このサイトマップのURLを LANGUAGES のすべてを使用して生成するかどうかを定義するブール値の属性です。デフォルトは False です。

languages

オプション。

i18n が有効のときに代替リンクを生成するために使用する 言語コード の sequence。デフォルトは LANGUAGES。

alternates

オプション。

真偽値属性。これを i18n と併用すると、生成される各URLには他言語バージョンを指す代替リンクのリストがあり、 hreflang attribute を使用します。デフォルトは False です。

x_default

オプション。

真偽値属性です。True の場合、 alternates によって生成された代替リンクには、 hreflang="x-default" フォールバックエントリーが含まれ、その値は LANGUAGE_CODE になります。デフォルトは False です。

get_latest_lastmod()[ソース]

オプション。 lastmod で返される最新の値を返すメソッド。この関数は、 Sitemap インデックス コンテキスト変数 に lastmod 属性を追加するために使用されます。

デフォルトでは、 get_latest_lastmod() は以下を返します:

  • lastmod が属性の場合:  lastmod 。

  • If lastmod is a method: The latest lastmod returned by calling the method with all items returned by items().

get_languages_for_item(item)[ソース]

オプション。 アイテムが表示される言語コードのシーケンスを返すメソッド。デフォルトでは、 get_languages_for_item() は languages を返します。

ショートカット

サイトマップフレームワークは、一般的なケースに対する便利なクラスを提供します。

class GenericSitemap(info_dict, priority=None, changefreq=None, protocol=None)[ソース]

The django.contrib.sitemaps.GenericSitemap class allows you to create a sitemap by passing it a dictionary which has to contain at least a queryset entry. This queryset will be used to generate the items of the sitemap. It may also have a date_field entry that specifies a date field for objects retrieved from the queryset. This will be used for the lastmod attribute and get_latest_lastmod() methods in the generated sitemap.

priority 、 changefreq、 protocol キーワード引数を使用すると、すべてのURLに対してこれらの属性を指定できます。

カスタマイズ例

以下は GenericSitemap を使用した URLconf の例です:

from django.contrib.sitemaps import GenericSitemap
from django.contrib.sitemaps.views import sitemap
from django.urls import path
from blog.models import Entry

info_dict = {
    "queryset": Entry.objects.all(),
    "date_field": "pub_date",
}

urlpatterns = [
    # some generic view using info_dict
    # ...
    # the sitemap
    path(
        "sitemap.xml",
        sitemap,
        {"sitemaps": {"blog": GenericSitemap(info_dict, priority=0.6)}},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

静的ビューのサイトマップ

検索エンジンのクローラに、オブジェクト詳細ページでもフラットページでもないビューをインデックスさせたいことがよくあります。その解決策は、 items にこれらのビューの URL 名を明示的に列挙し、サイトマップの location メソッドで reverse() を呼び出すことです。例えば次のようにします:

# sitemaps.py
from django.contrib import sitemaps
from django.urls import reverse


class StaticViewSitemap(sitemaps.Sitemap):
    priority = 0.5
    changefreq = "daily"

    def items(self):
        return ["main", "about", "license"]

    def location(self, item):
        return reverse(item)


# urls.py
from django.contrib.sitemaps.views import sitemap
from django.urls import path

from .sitemaps import StaticViewSitemap
from . import views

sitemaps = {
    "static": StaticViewSitemap,
}

urlpatterns = [
    path("", views.main, name="main"),
    path("about/", views.about, name="about"),
    path("license/", views.license, name="license"),
    # ...
    path(
        "sitemap.xml",
        sitemap,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

サイトマップインデックスを作成する

views.index(request, sitemaps, template_name='sitemap_index.xml', content_type='application/xml', sitemap_url_name='django.contrib.sitemaps.views.sitemap')

サイトマップフレームワークには、 sitemaps 辞書で定義された各セクションごとに1つずつ、個別のサイトマップファイルを参照するサイトマップインデックスを作成する機能もあります。使用上の唯一の違いは下記です:

上記の例に対する関連するURLconfの行は、次のようになります:

from django.contrib.sitemaps import views

urlpatterns = [
    path(
        "sitemap.xml",
        views.index,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.index",
    ),
    path(
        "sitemap-<section>.xml",
        views.sitemap,
        {"sitemaps": sitemaps},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

これにより、自動的に sitemap.xml ファイルが生成され、 sitemap-flatpages.xml と sitemap-blog.xml の両方が参照されます。 Sitemap クラスと sitemaps 辞書は全く変わりません。

If all sitemaps have a lastmod returned by get_latest_lastmod() the sitemap index will have a Last-Modified header equal to the latest lastmod.

サイトマップの URL が 50,000 を超える場合は、インデックスファイルを作成すべきです。この場合、 Django は自動的にサイトマップをページ分割し、インデックスに反映します。

通常のサイトマップビューを使用していない場合 (たとえば、キャッシュデコレータでラップされている場合) は、サイトマップビューに名前を付けて、インデックスビューに sitemap_url_name を渡さなければなりません:

from django.contrib.sitemaps import views as sitemaps_views
from django.views.decorators.cache import cache_page

urlpatterns = [
    path(
        "sitemap.xml",
        cache_page(86400)(sitemaps_views.index),
        {"sitemaps": sitemaps, "sitemap_url_name": "sitemaps"},
    ),
    path(
        "sitemap-<section>.xml",
        cache_page(86400)(sitemaps_views.sitemap),
        {"sitemaps": sitemaps},
        name="sitemaps",
    ),
]

テンプレートをカスタマイズする

サイト上で利用可能な各サイトマップやサイトマップインデックスごとに異なるテンプレートを使用したい場合は、URLconf を介して sitemap ビューや index ビューに template_name パラメータを渡すことで指定できます:

from django.contrib.sitemaps import views

urlpatterns = [
    path(
        "custom-sitemap.xml",
        views.index,
        {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
        name="django.contrib.sitemaps.views.index",
    ),
    path(
        "custom-sitemap-<section>.xml",
        views.sitemap,
        {"sitemaps": sitemaps, "template_name": "custom_sitemap.html"},
        name="django.contrib.sitemaps.views.sitemap",
    ),
]

これらのビューは TemplateResponse インスタンスを返し、レンダリング前のレスポンスデータを簡単にカスタマイズできます。詳細は TemplateResponse のドキュメント を参照してください。

コンテキスト変数

テンプレートをカスタマイズする際に、 index() と sitemap() ビューには、以下のコンテキスト変数に依存できます。

インデックス

変数 sitemaps は各サイトマップの location と lastmod 属性を含むオブジェクトのリストです。各URLは以下の属性を持ちます:

  • location: サイトマップの場所 (URLとページ)。

  • lastmod: 各サイトマップに対して get_latest_lastmod() メソッドによって設定されます。

サイトマップ

変数 urlset は、サイトマップに表示されるべきURLのリストです。各URLは、 Sitemap クラスで定義された属性を公開しています。

  • alternates

  • changefreq

  • item

  • lastmod

  • location

  • priority

alternates 属性は、 i18n と alternates が有効になっている場合に利用可能です。それは、各URLに対してオプションの x_default フォールバックを含む、他の言語バージョンのリストです。各代替バージョンは、location と lang_code キーを持つ辞書です。

The item attribute has been added for each URL to allow more flexible customization of the templates, such as Google news sitemaps. Assuming Sitemap's items() would return a list of items with publication_data and a tags field something like this would generate a Google News compatible sitemap:

<?xml version="1.0" encoding="UTF-8"?>
<urlset
  xmlns="https://www.sitemaps.org/schemas/sitemap/0.9"
  xmlns:news="https://www.google.com/schemas/sitemap-news/0.9">
{% spaceless %}
{% for url in urlset %}
  <url>
    <loc>{{ url.location }}</loc>
    {% if url.lastmod %}<lastmod>{{ url.lastmod|date:"Y-m-d" }}</lastmod>{% endif %}
    {% if url.changefreq %}<changefreq>{{ url.changefreq }}</changefreq>{% endif %}
    {% if url.priority %}<priority>{{ url.priority }}</priority>{% endif %}
    <news:news>
      {% if url.item.publication_date %}<news:publication_date>{{ url.item.publication_date|date:"Y-m-d" }}</news:publication_date>{% endif %}
      {% if url.item.tags %}<news:keywords>{{ url.item.tags }}</news:keywords>{% endif %}
    </news:news>
   </url>
{% endfor %}
{% endspaceless %}
</urlset>