sitemaps フレームワーク

revision-up-to:11321 (1.1)

Django には、 サイトマップ XML ファイルを簡単に生成できる高水準 のサイトマップ生成フレームワークが付属しています。

概要

サイトマップ (sitemap) とは、自分のサイト上のページの更新頻度や特定のペー ジ間の「重要度」を検索エンジンのインデクサに対して知らせるために、Web サイ ト上に配置する XML ファイルです。この情報があると、検索エンジンがサイトのイ ンデクスを生成するときに役立ちます。

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

sitemaps は Django の 配信フレームワーク によく似ています。サイトマップの生成は簡単で、ただ Sitemap クラスを書いて、 URLconf に指定するだけです。

インストール

sitemaps アプリケーションは以下の手順でインストールします:

  1. INSTALLED_APPS 設定に 'django.contrib.sitemaps' を加 えます。
  2. TEMPLATE_LOADERS 設定に、 'django.template.loaders.app_directories.load_template_source' が入っているか確かめます。デフォルトの設定ファイルには入っているので、 注意が必要なのは設定を変更している時だけです。
  3. sites フレームワーク をインストールし ておいてください。

(注意: sitemaps アプリケーションは、データベースに何らテーブルをインストール しません。 INSTALLED_APPSsitemaps を入れておかねばならな いのは、 load_template_source() テン プレートローダがデフォルトのテンプレートを捜し出せるようにするためです。)

初期化

自分の Django サイト上でサイトマップ生成を行わせるには、 URLconf に以下の行を追加します:

(r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps})

これで、 Django はクライアントが /sitemap.xml にアクセスしたときに サイトマップを生成するようになります。

サイトマップファイルの名前はさして重要ではありませんが、ファイルの場所は重 要です。検索エンジンは、サイトマップ内のリンクをインデクス化する際、ファイ ルの置かれている URL レベルとその下のリンクしかたどりません。例えば、 sitemap.xml がルートディレクトリ下にあれば、 Google はサイト上の全 ての URL を参照します。一方、サイトマップの場所が /content/sitemap.xml であれば、 /content/ で始まる URL しか 参照しません。

ビュー関数 sitemap() には、必須の引数 {'sitemaps': sitemaps} があり ます。 sitemaps はセクションラベル (例えば blognews) を、 Sitemap クラス (例えば BlogSitemapNewsSitemap) に対応づける辞書にします。あるいは、 Sitemap クラスの インスタンス (例えば BlogSitemap(some_bar)) でもかまいません。

Sitemap クラス

Sitemap クラスとは、サイトマップ上のエン トリの「セクション」を表現するための Python のクラスです。例えば、ある Sitemap クラスはブログ上の全てのエントリ を表し、別のクラスはイベントカレンダー上の全てのイベントを表現する、といっ た具合です。

最も単純化すれば、全てのセクションは sitemap.xml という一つのファイ ルにまとめあげられることになります。とはいえ、 sitemaps フレームワークを使 えば、各セクションごとに個別のサイトマップファイルがあるようなサイトマップ インデクスを生成できます (後述の サイトマップインデクスを生成する を参照 してください)。

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

簡単な例

ブログシステムを使っていて、 Entry というモデルがあるとしましょう。 サイトマップに全てのブログエントリへのリンクを含めたければ、サイトマップク ラスは以下のようになります:

from django.contrib.sitemaps import Sitemap
from mysite.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

注意点:

  • changefreqpriority はクラス属性 で、それぞれ <changefreq> および <priority> エレメントに対応 しています。これらの属性は、上の例の lastmod のよう に、メソッドとしても定義できます。
  • items() はオブジェクトのリストを返すだけのメソッドで す。このメソッドの返すオブジェクトは、サイトマップの各プロパティ (location, lastmod, changefreq, priority) に対応するメ ソッドに渡されます。
  • lastmod は Python の datetime オブジェクトを返さ ねばなりません。
  • この例には location メソッドがありませんが、自分でメ ソッドを定義して、オブジェクトの URL を指定してもかまいません。デフォ ルトでは、 location() は各オブジェクトに対して get_absolute_url() を呼び出し、その結果を返します。

Sitemap クラスリファレンス

class Sitemap

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

items

必須です。 オブジェクトのリストを返すメソッドです。フレームワー クはオブジェクトの が何であるかを問いません。重要なのは、オブ ジェクトが location(), lastmod(), changefreq(), priority() といった メソッドに渡されるという点だけです。

location

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトに対する絶対 URLの文字列を計算して返 さねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われる絶対 URL を表す文字列にしま す。

いずれの場合も、「絶対 URL」とは、以下の例のようにプロトコルおよび ドメイン部を含まない URLを指します:

  • 正しい: '/foo/bar/'
  • 誤り: 'example.com/foo/bar/'
  • 誤り: 'http://example.com/foo/bar/'

location を指定していない場合、フレームワークは items() の返す各オブジェクトに対して get_absolute_url() メソッドを呼び出します。

lastmod

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトの最終更新日時を Python の datetime.datetime オブジェクトで返さねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われるオブジェクトの最終更新日時を Python の datetime.datetime オブジェクトで返さねばなりません。

changefreq

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトの更新頻度を Python の文字列型で返さ ねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われるオブジェクトの更新頻度を Python の文字列型で返さねばなりません。

メソッド、属性を問わず、 changefreq の値は以下のい ずれかにします:

  • 'always'
  • 'hourly'
  • 'daily'
  • 'weekly'
  • 'monthly'
  • 'yearly'
  • 'never'
priority()

省略可能です。 メソッドまたは属性です。

メソッドとして定義する場合、 items() の返すオブジェ クトを引数にとり、オブジェクトの重要度 (priority) を Python の文字 列型か浮動小数型で返さねばなりません。

属性として定義する場合、 items() の返す 全てのオブジェクトに共通して 使われるオブジェクトの重要度を Python の文字列型か浮動小数型で返さねばなりません。

priority の値は 0.41.0 のようにします。 デフォルトの重要度は 0.5 です。重要度の詳細は sitemaps.org のドキュメント を参照してください。

ショートカット

sitemaps フレームワークでは、よく使われる状況向けに、二つの便宜クラスを用意 しています:

class FlatPageSitemap

django.contrib.sitemaps.FlatPageSitemap クラスは、現在の SITE_ID (sites のドキュメント 参照) 向けの全ての フラットページ を 検索し、サイトマップのエントリを生成します。各エントリには location 属性だけが設定され、 lastmod, changefreq, priority は設定されません。

class GenericSitemap

django.contrib.sitemaps.GenericSitemap クラスは任意の 汎用ビュー <ref-generic-views> と組み合わせて使えます。 GenericSitemap を使うには、汎用ビュー に渡すのと同じ info_dictGenericSitemap に渡してインスタンスを 生成します。 info_dict には少なくとも queryset がなけれ ばなりません。また、 info_dictqueryset で取り出され るオブジェクトの日時のフィールドを指定する date_field エントリ がある場合、サイトマップ生成時にエントリの lastmod 属 性に使われます。 GenericSitemap のコ ンストラクタには、 prioritychangefreq といったキーワード引数も指定できます。 これらの引数の値は、全ての URL に共通の属性になります。

FlatpageSitemapGenericSitemap の両方を組み込んだ URLconf の例は以下のようになります:

from django.conf.urls.defaults import *
from django.contrib.sitemaps import FlatPageSitemap, GenericSitemap
from mysite.blog.models import Entry

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

sitemaps = {
    'flatpages': FlatPageSitemap,
    'blog': GenericSitemap(info_dict, priority=0.6),
}

urlpatterns = patterns('',
    # info_dict を使った汎用ビューの設定
    # ...

    # サイトマップ
    (r'^sitemap.xml$', 'django.contrib.sitemaps.views.sitemap',
        {'sitemaps': sitemaps})
)

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

sitemap フレームワークには、個々のサイトマップファイルを参照するサイトマッ プインデクスを生成する機能もあります。サイトマップインデクスからサイトマッ プファイルへの参照は、 sitemaps 辞書に定義されている各セクションご とにひとつづつ作成されます。サイトマップインデクスを使うには、少しだけやり 方を変えます:

  • URLconf に、 django.contrib.sitemaps.views.index()django.contrib.sitemaps.views.sitemap() という二つのビューを使 います。
  • django.contrib.sitemaps.views.sitemap() にキーワード引数 section を指定します。

上の例にならうと、URLconf は以下のようになります:

(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', {'sitemaps': sitemaps}),
(r'^sitemap-(?P<section>.+)\.xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),

この設定では、 sitemap-flatpages.xmlsitemap-blog.xml へ の参照が入った sitemap.xml が自動生成されます。 Sitemap クラスと sitemaps 辞書に 手を加える必要はありません。

50,000 以上の URL を含むサイトマップの場合、インデクスファイルを生成せねば なりませんが、 Django は自動的にサイトマップをページ分割し、インデクスにそ の内容を反映します。

Google に ping を打つ

サイトマップの変更時に、Google に「ping を打」って、サイトのインデクスを再 構築させたい場合もあるでしょう。 sitemap フレームワークで ping を打つには、 django.contrib.sitemaps.ping_google()`() を呼び出します。

ping_google()

ping_google() にはオプションの引数 sitemap_url がありま す。この引数にはサイトのサイトマップの絶対 URL (例えば '/sitemap.xml')を指定します。 sitemap_url を指定しなかっ た場合、 ping_google() は URLconf の逆引きを行って、サイトマップ の在処を探します。

サイトマップの URL を捜し出せなかった場合、 ping_google()django.contrib.sitemaps.SitemapNotFound 例外を送出します。

Google に登録しておきましょう!

ping_google() が動作するのはは、 Google Webmaster Tools でサイ トを登録してある場合だけです。

ping_google() の用法として有用なのは、モデルの save() メソッド で呼び出すというものです:

from django.contrib.sitemaps import ping_google

 class Entry(models.Model):
     # ...
     def save(self, force_insert=False, force_update=False):
         super(Entry, self).save(force_insert, force_update)
         try:
             ping_google()
         except Exception:
             # Bare 'except' because we could get a variety
             # of HTTP-related exceptions.
             pass

とはいえ、 ping_google() は Google のサーバに HTTP リクエストを送信 するので、 save() のたびにネットワークアクセスのオーバヘッドが生じます。 もっと効率的にやりたければ、 cron 化されたスクリプトなど、一定の時点で実行 するようスケジュールしたタスクの中で ping_google() を呼び出すとよい でしょう。

manage.py で Google に Ping を送信する

Django 1.0 で新たに登場しました: リリースノートを参照してください

サイトマップアプリケーションをプロジェクトに追加したら、 manage.py コマ ンドラインインタフェースを使って、以下のように Google サーバに ping を送信 できます:

python manage.py ping_google [/sitemap.xml]