Djangoでサイトマップを動的に生成する方法
2016/06/14 00:28
  • 技術トピックは久しぶりです。
    Djangoでサイトマップを作った時のメモを載せたいと思います。

    はじめに

    Googleサーチコンソール(旧ウェブマスターツール)をサイトに導入していることを前提とします。

    サーチコンソールではサイトのsitemap.xmlを登録(Googleさんに通知)することで、Googleからのクロール速度を早めることができます。
    それにより、通常(何もしない)より早く検索結果のインデックスに登録される、というわけです。

    今回は、Djangoプロジェクトにおいて、どのようにsitemap.xmlを動的生成させるかということに主眼をおいたメモです。

    準備編:Djangoにsitemaps, siteアプリをインストールする

    DjangoにはSitemapを生成するアプリがすでに用意されているので、それを使います。

    settings.py に以下を追加します。

    INSTALLED_APPS = (
        ....
        'django.contrib.sites',
        'django.contrib.sitemaps',
    )
    

    一つ目の"sites"は、どのプロジェクトのサイトマップを作るかを指定するために必要です。
    二つ目の"sitemaps"は文字通りサイトマップを作成するためのアプリケーションです。

    管理画面からサイト登録する

    この時点で、Djangoの管理サイトに"サイト"という項目が表示されるので、自分のサイトを登録します。
    IDの1番にはexample.comのようなサンプルサイトが予め登録されているので、それを編集しましょう。

    当サイトの場合、

    ドメイン名: 4to.pics
    表示名: 4to.pics

    のように設定します。

    settings.pyにSITE_IDを追加する

    続いて、settings.pyにいまサイト登録したIDを記載します。

    SITE_ID = 1
    

    これで、Djangoでsitemap.xmlを生成する下準備が整いました。

    sitemaps.pyの作成

    続いて、sitemaps.pyを作成します。

    格納する場所はアプリケーションの直下、models.pyとかviews.pyが置かれているところに設置すればよいでしょう。

    from django.contrib.sitemaps import Sitemap # sitemapアプリのインポート
    from .models import * 
    # 略式で書いています。python的には、必要なモデルを一つずつ列挙していくのが推奨されていると思いますが
    # ここでは省略します。
    
    
    class IndexSitemap(Sitemap):
        def items(self):
            return ['top']
    
        def location(self, obj):
            return '/'
    

    上記は必要最低限ですが、例えばこんな感じで記載してやります。

    IndexSitemapというclassをまず設定してやります。文字通り、サイトトップとなる箇所です。
    itemsのreturn ['top']は、なんでもいいです。ただの名前です。笑
    トップページだよ、と明示的に示したかったのでそう指定しました。

    locationのreturn '/'は、サイトマップさんに、このIndexSitemapクラスはサイトのルートパスを指定しますよ、という設定です。

    ブログの記事など、動的に生成されるページに関しては、以下のようにしてやります。

    sitemaps.py

    class BlogDetailSitemap(Sitemap):
    
        def items(self):
            return Blog.objects.all()
    

    さらに、models.pyを以下のように変更
    # この行を追記
    from django.core.urlresolvers import reverse
    ...
    ...
    class Blog(models.Model):
        subject = models.CharField(max_length=255)
        content = models.TextField(blank=False)
        is_publish = models.BooleanField(default=False)
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)
        ...
        
        # ここを追記
        # BlogDetailはurls.pyのurl_patternsで指定した個別記事URLのnameを指定する
        # url(r'^blog/post/(?P<pk>\d+)$', views.BlogDetailView.as_view(), name='BlogDetail')
        def get_absolute_url(self):
            return reverse('BlogDetail', kwargs={'pk': self.id})
    
    

    urls.pyに追記する

    続いて、アプリケーションのurls.pyに追記していきます。
    from mySite import sitemaps as mysm # mySiteはアプリケーション名、先ほど作ったsitemaps.pyの読み込み
    from django.contrib.sitemaps.views import sitemap
    
    sitemaps = {
        'index': mysm.IndexSitemap,
        'blog': mysm.BlogDetailSitemap,
    }
    

    ここのsitemapsオブジェクトのkeyになっている"index"は、まぁ正直なんでもいいですw
    わかりやすいように命名してあげましょう。(urlpatternsにつけたnameにするなり)

    その後、urlpatternsにサイトマップ用のパスを指定してあげます。どんな名前でもいけますが、素直にsitemap.xmlとしましょう。

    urlpatterns = [
        ...
        url(r'^sitemap\.xml$', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
    ]
    

    これで、ドキュメントルート直下のsitemap.xmlというファイル名に対して、ルーティングできました。

    実際にsitemap.xmlにアクセスしてみる。

    多くの方の場合、開発環境はpython manage.py runserverで動かしていると思いますので、
    http://127.0.0.1:8000/sitemap.xmlをChromeで見てみましょう。(safariだときちんとXMLが表示されないので)

    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
        <url>
            <loc>http://127.0.0.1:8000/</loc>
        </url>
        <url>
            <loc>http://127.0.0.1:8000/blog/post/1</loc>
        </url>
        <url>
            <loc>http://127.0.0.1:8000/blog/post/2</loc>
        </url>
        <url>
            <loc>http://127.0.0.1:8000/blog/post/3</loc>
        </url>
    </urlset>
    

    上記のように表示されれば成功です。

    長くなりましたが、今回は以上です。
    現状だと、まだsitemap.xmlが動的生成されただけで、Googleへの通知はサーチコンソールから手動で行う必要があります。
    DjangoのsitemapsアプリケーションにはGoogleに自動的に通知してくれる機能も備えていますので、
    そちらは改めて紹介できればと思います。

    人気ブログランキングへ ブログランキング・にほんブログ村へ
    ↑応援よろしくお願いします!m(_ _)m

  • <2016/06/14 00:25>
  • Python
  • DjangoSitemap.xmlサイトマップ自動生成
  • 新しい記事へ
    来週末は一時帰国

    古い記事へ
    最近欲しい本

profile picture

自己紹介的な何か

@wkmettyでついったーやってます。時々。 6年間勤めたゲーム会社を2018年2月に退職しフリーランスのプログラマに。 WordPress Core, WP-CLI コントリビューター。 お仕事募集中です。