djangoテンプレートとJIjaテンプレートを混合します.


Djangoはずっと論争されているところはテンプレート機能です.その中で一番印象深いのはpython-cnで最初にテンプレートとあまり関係のないテーマによって引き起こされた大討論です.
お目にかかる turbogeassを聞いているやつはdjangoがzopeに学ぶべきだと言っています.­なんですか
http://groups.google.com/group/python-cn/browse_thread/thread/c 32 a 8 ba 1 b 2 e 1 f 5 f 3
 
論争の焦点は主にdjangoのテンプレート機能が弱すぎて、拡張されたfilterに集中しています.
 
Django自身の観点:
Djangoテンプレート自体は設計当初からもっと多くのことを考慮して、テンプレートの使用者はページ設計者であり、バックグラウンドプログラマではないので、できるだけ簡単に設計されています.設計上はテンプレートの不適切な使用を制限して、作業責任をよりよく区別するために、この点はテンプレート部分のドキュメントは最初から直接に二つに分けられています.上記の2種類の人にそれぞれ適して詳しく読めば分かります.
 
バックグラウンドプログラマの観点:
Djangoの利用者は後で台のプログラマがメインになるかもしれないので、多くの人はDjangoのテンプレートを改善することを強く求めています.しかし、Djangoの開発チームはこの要求に対して終始無関心であった.そこで、他のテンプレートエンジンが現れました.例えば、ジンジャーです.
 
ジンジャジャ2
ジンジャーの使用はDjangoと似ていますが、主に「%」と「%」という二つのものの中でテンプレートを使ってレンダリングします.しかし、ジンジャーはテンプレートの中でpython形式のコードを多く使うことを許可します.これはいつかとても便利です.同時にジンジャーは自分でdjangoのテンプレートエンジンよりもっと良い性能を持つと宣言しました.
 
Djangoではジンジャジャ2を使用します.
現在紹介されているDjangoでは、JIN ja 2を使用していますが、主に様々な方法でDjangoの既存のテンプレートを交換しています.最近は『Pro Django』を見ていますが、その中で第6章でテンプレートを紹介する時に、もう一つの方法がdjangoでジンジャ2を使うと提案されました.
このような方式はユーザー定義によって、該当するendの文字が必要で、そしてrenderの時に、これを直接jinja 2に伝えて処理するので、この対中の内容はジンjaの文法を使ってもいいです.他の部分はdjangoのテンプレート文法に適合しています.これは、少しだけジンジャ2を使う場合には、完全な入れ替えよりも、時間を省き、よりすっきりとした仕上がりになります.以下はdjangoとJIN ja 2を混ぜて使うコードの例です.
ビュー部分:
# Create your views here.
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template import RequestContext

def test(request):
    user = 'myuser'
    seq = [1,2,3]
    def sum(a,b):
        return a + b
    return render_to_response('jinja_test.html', 
                              {'user':user, 'seq':seq, 'sum':sum,}, 
                              context_instance=RequestContext(request))
 
テンプレートコード:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
        <title>jinja_tag test</title>
    </head>
    <body>
    	{%load jinja_tag%}
		{%jinja%}
			{% for item in seq - %}
				{{ item }}
			{% - endfor %}
			<br />
			{{ 1+1*4 }}
			<br />
			{{ sum(1, seq[2]) }}
			<br />
		{%endjinja%}
    </body>
</html>
 
上から見れば、%jinja%と「%endjinja%」の間のコードはジンジャジャ文法を使用していますが、他の部分はまだdjangoのテンプレート文法に制限されています.
 
実装:
実はこのようなjinjaを実現しました.具体的な原理は『pro django』の原書を読むことができます.ここでは修正されたものだけを貼り付けて、いくつかの小さいbugのコードを修復しました.
import jinja2
from django import template

register = template.Library()

def string_from_token(token):
    """
    Converts a lexer token back into a string for use with Jinja.
    """
    if token.token_type == template.TOKEN_TEXT:
        return token.contents
    elif token.token_type == template.TOKEN_VAR:
        return '%s %s %s' % (
            template.VARIABLE_TAG_START,
            token.contents,
            template.VARIABLE_TAG_END,
        )
    elif token.token_type == template.TOKEN_BLOCK:
        return '%s%s%s' % (
            template.BLOCK_TAG_START,
            token.contents,
            template.BLOCK_TAG_END,
        )
    elif token.token_type == template.TOKEN_COMMENT:
        return u'' # Django doesn't store the content of comments

@register.tag
def jinja(parser, token):
    """
    Define a block that gets rendered by Jinja, rather than Django's templates.
    """
    bits = token.contents.split()
    if len(bits) != 1:
        raise template.TemplateSyntaxError, "'%s' tag doesn't take any arguments." % bits[0]

    # Manually collect tokens for the tag's content, so Django's template
    # parser doesn't try to make sense of it.
    contents = []
    while 1:
        try:
            token = parser.next_token()
        except IndexError:
            # Reached the end of the template without finding the end tag
            raise template.TemplateSyntaxError("'endjinja' tag is required.")
        if token.token_type == template.TOKEN_BLOCK and token.contents == 'endjinja':
            break
        contents.append(string_from_token(token))
    contents = ''.join(contents)
    return JinjaNode(contents)

class JinjaNode(template.Node):
    def __init__(self, contents):
        self.template = jinja2.Template(contents)

    def render(self, context):
        # Jinja can't use Django's Context objects, so we have to
        # flatten it out to a single dictionary before using it.
        jinja_context = {}
        for layer in context:
            for key, value in layer.items():
                if key not in jinja_context:
                    jinja_context[key] = value
        return self.template.render(jinja_context)
 
より良い集積:
上のHTMLテンプレートのコードの中で、毎回このタグを使う必要がある時、このステップを通過します.面倒くさいです.
実はこのタグをdjangoと同じbuiltinに追加してもいいです.内蔵のように使ってもいいです.
あるアプリのカタログの下にあるだけです.init_.pyファイルに以下のコードを追加すれば実現できます.
from django.template import add_to_builtins
# Uncomment the next line to enable the jinja_tag as if defaulttags
add_to_builtins('jinja_tag.templatetags.jinja_tag')
 
デモとソースコードのダウンロード:
デモ:http://www.playdjango.cn/jinja/
ソースコード及び使用基準:http://code.google.com/p/django-demo-apps/source/browse/#svn/trunk/demo/jinja_タグ