2009年12月6日日曜日

Django テンプレートタグを自作する

 テンプレートに可変長のリストを渡してテーブルを作る必要があった。で、cycle タグを使って何とかならないかと思ってやったら出来た。

 が、そこのコードをループで回すと2回目のループの最初が、直前のループの最後の続きになってしまう。

 色々やったがうまくいかない。よし、フィルターを作ってやろうと、作った。出来上がったのだが、表示内容が checkbox + txt だったので、このままでは使えず(フィルターの側に check box の html を入れるわけにも行くまい)。

 で、reset できる cycle タグを作ればよかろうと取り掛かったのだが...。丸々二日も掛かってしまった。
 もともとの cycle タグのコードや、ドキュメントを見ながらやったのだが、なかなか難解。テンプレートに対するコンパイルの概念を理解するまで一苦労。出来上がったオブジェクトにメンバ変数インスタンスにアトリビュートを後から自由に追加できるなんてのは、知ってはいたが実際に使われるところを見ると目からウロコ。

 とりあえず、今の段階でのコードはこんな感じ。まぁ、ほとんどは cycle タグの流用なんだけど (^^;
class CycleNode_R(Node):
def __init__(self, cyclevars, variable_name=None):
# self.str_list = [Variable(v) for v in cyclevars]
self.str_list = [unicode(v).replace("'", "") for v in cyclevars]
self.num = len(cyclevars)
self.cnt = 0

def render(self, context):
value = self.str_list[self.cnt]
self.cnt += 1
if self.cnt == self.num: self.cnt = 0
return value
def reset(self):
self.cnt = 0

def cycle_r(parser, token):
args = token.split_contents()

if len(args) < 2:
raise TemplateSyntaxError("'cycle' tag requires at least two arguments")

if len(args) == 2:
# {% cycle foo %} case.
name = args[1]
if not hasattr(parser, '_namedCycleNodes_R'):
raise TemplateSyntaxError("No named cycles in template. '%s' is not defined" % name)
if not name in parser._namedCycleNodes_R:
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return parser._namedCycleNodes_R[name]

if len(args) > 4 and args[-2] == 'as':
name = args[-1]
node = CycleNode_R(args[1:-2], name)
if not hasattr(parser, '_namedCycleNodes_R'):
parser._namedCycleNodes_R = {}
parser._namedCycleNodes_R[name] = node
else:
node = CycleNode_R(args[1:])
return node
cycle = register.tag(cycle_r)

class cycle_rrr(Node):
def __init__(self,base):
self.base = base
def render(self,context):
self.base.reset()
return ''

def cycle_rr(parser, token):
args = token.split_contents()

if len(args) < 2:
raise TemplateSyntaxError("'cycle' tag requires at least two arguments")

if len(args) == 2:
# {% cycle foo %} case.
name = args[1]
if not hasattr(parser, '_namedCycleNodes_R'):
raise TemplateSyntaxError("No named cycles in template. '%s' is not defined" % name)
if not name in parser._namedCycleNodes_R:
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return cycle_rrr(parser._namedCycleNodes_R[name])
cycle = register.tag(cycle_rr)
 書式は cycle と基本的に同じで、リセットしたいタイミングに cycle_rr をおけばオーケ。

0 件のコメント:

コメントを投稿