Doge log

Abby CTO 雑賀 力王のオフィシャルサイトです

なんていうのか横に出てくるside-bar?Navigation?module?っていうのを実装

Templateを使うタグの作り方。
またしても参考程度に。
はてななんかでもあるようにサイドバーとかに過去の記事のアーカイブを月度表示とかさせるわけだがあーいうのをタグでできないかなと。

何故タグか?

えー?generic-viewの結果を埋めたらいいんじゃね?って感じだけども。
実際includeだと以下のような問題がある。

  • レンダリングするデータを元のContextが持っていないといけない(複雑)
  • レイアウトが崩れる
  • extend無限ループが発生する可能性がある(templateの使いまわし)

なのでタグかなと。
タグだと他のページに埋めるの非常に簡単だし。

タグを作る

今回はサイドバー用に月度アーカイブを表示させるタグの作ってみます。
で、できました!隊長殿!
仕組みさえわかれば20分くらいでいけると思われ。
(もっと早いか)

archive.py
from djangojapan.blog.models import Entry
from django.template import Node, Library, loader
import datetime, time

register = Library()

class YearArchiveNode(Node):
    
    def __init__(self, year):
        self.year = year
        
    def render(self, context):
        year = self.year
        queryset = Entry.objects.all();
        now = datetime.datetime.now()
        lookup_kwargs = {'pub_date__year': year}
        # Only bother to check current date if the year isn't in the past.
        if int(year) >= now.year:
            lookup_kwargs['pub_date__lte'] = now
        date_list = queryset.filter(**lookup_kwargs).dates('pub_date', 'month')
        t = loader.get_template('blog/archive/entry_archive_year')
        context['date_list'] = date_list
        context['year'] = year        
        output = t.render(context)
        return output

def do_get_year_archive(parser, token):
    tokens = token.contents.split()
    year = tokens[2]
    if not year:
        now = datetime.datetime.now()
        year = now.year
    return YearArchiveNode(year)

register.tag('get_year_archive', do_get_year_archive)

えーっとタグの説明は見たとおりって感じです。
ざっくりですが流れは以下

  1. 指定した年のアーカイブを作るYearArchiveNodeを定義
  2. Blogのエントリーを月ごとに取得
  3. 結果をcontextにセット
  4. 結果をtemplateにレンダリングレンダリング結果を返す
  5. これを"get_year_archive"って名前でタグを登録します。

うーむ。ふつーにgeneric-viewのtemplateでない事に注意。

        t = loader.get_template('blog/archive/entry_archive_year')

これの理由は元々のgeneric-viewで使ってるtemplateはextendしてるのでそれを入れ込むとレイアウトが崩れるため。
実際のtemplateはこれ

blog/archive/entry_archive_year.html
<h2>Archives</h2>
{% for date in date_list %}
<ul>
	<li><a href="/blog/{{date|date:"Y"}}/{{date|date:"m"}}">{{date|date:"Y/m"}}</a></li>
</ul>
{% endfor %}

これならextendしてないので崩れません。
あとTips的な話ですが

date_list = queryset.filter(**lookup_kwargs).dates('pub_date', 'month')

のdatesメソッドは取得するフィールドと種類をセットしてグループ化するメソッドです。
XXごとに〜なんて処理を行う場合には重宝します。
でタグの作成は終わりです。

実際に使う

実際これを使うhtmlには

index.html
{% load archive %}
{% get_year_archive as 2006 %}

と記述するだけです。
簡単ですね。
ちなみに先ほど作成したタグのメソッドで"token"って出てきたと思いますが。

def do_get_year_archive(parser, token):
    tokens = token.contents.split()
    year = tokens[2]

それは

{% get_year_archive as 2006 %}

のタグ内の文字列を指します。
なのでこのケースでは"tokens"には

  1. get_year_archive
  2. as
  3. 2006

が入ります。

終わり

一応月度っていっても年指定しないといけないのが難点かも。
(datesメソッド次第だな)

今回は月度ですが日別なんかも簡単に作れますね。

うーん、これはけっこー重要なサンプルかも。
ちなみに本家djangoサイトのweblog

<h2>Archives</h2>
<ul class="linklist">
	<li><a href="/weblog/2006/jan/">January 2006</a></li>
	<li><a href="/weblog/2005/dec/">December 2005</a></li>
  <li><a href="/weblog/2005/nov/">November 2005</a></li>
	<li><a href="/weblog/2005/oct/">October 2005</a></li>
	<li><a href="/weblog/2005/sep/">September 2005</a></li>
	<li><a href="/weblog/2005/aug/">August 2005</a></li>
	<li><a href="/weblog/2005/jul/">July 2005</a></li>
</ul>

直書きかあ・・・・。

うくく。