锁定老帖子 主题:混合使用django模板和jinja模板
该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-02-27
Django一直广受争论的地方就是它的模板功能,其中印象最深的一次是在python-cn上最初由一个与模板不太相关的主题引起的大讨论。 见 《听一个turbogears的家伙讲django该向zope学什么》 http://groups.google.com/group/python-cn/browse_thread/thread/c32a8ba1b2e1f5f3
争论的焦点主要集中在django的模板功能太弱,扩展的filter,tag难写,是否应该在模板中直接允许执行更多的python代码等。
Django本身的观点: Django模板本身从设计之初就更多的考虑到模板的使用者是 页面设计人员 而非 后台程序员 , 所以设计的尽可能简单,从设计上去限制模板的不规范使用,以便更好的区分工作责任,这点从它的模板部分文档从最初就直接分为两份,分别适合以上两种人员进行细读就可以看出来。
后台程序员的观点: 或许Django的使用者以后台程序员为主,所以很多人都强烈要求改进Django的模板,以便可以更方便的直接调用python代码。但是Django的开发团队对此要求始终无动于衷。于是出现了其他的一些 模板引擎,比如jinja 。
jinja2 jinja的使用上和Django及其相似,都主要通过 {{ }} 和{% %} 这两个东西里进行模板渲染,但是jinja允许你在模板中更多的使用python形式的代码。这在某些时候是的确是非常方便的。同时jinja自己宣称它比django的模板引擎拥有更好的性能。
在Django中使用jinja2: 目前介绍在Django中使用jinja2的方式主要都是通过各种方式替换Django原有模板。最近看 《Pro Django》,其中第6章介绍模板的时候,提出了另一种在django中使用jinja2的方式。 这种方式是通过自定义一个需要有相应end的tag,然后在render的时候,将此对tag中的原始内容直接传给jinja2进行处理,因此此对tag之间的内容就可以使用jinja的语法,而其他部分仍需符合django的模板语法。这对于只需要少量使用jinja2的情况下,相对于完整替换,这种方式更省时省力,也显得更干净利落。下面就是混合使用django和jinja2的代码示例: view部分: # 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%}之间的代码使用jinja语法,而其他部分仍然限制在django的模板语法。
实现: 其实实现这样一个jinja tag是非常容易的,具体原理可以看《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模板代码中,每次需要使用该 tag 的时候,都要经过 {%load jinja_tag%} 这个步骤,显得很麻烦。 其实可以将该 tag 添加到和django同样的builtin中,那样就可以像使用内置tag一样使用该tag了。 只需要 在 某个app目录下的 __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')
demo和源代码下载: demo: http://www.playdjango.cn/jinja/ 源代码及使用参考: http://code.google.com/p/django-demo-apps/source/browse/#svn/trunk/demo/jinja_tag
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2009-02-27
可惜jinja2方法调用一定要用(),否则真的是转换很方便的
|
|
返回顶楼 | |
发表时间:2009-02-28
很好!
django的模板太tmd的弱了 |
|
返回顶楼 | |
发表时间:2009-02-28
guotie 写道 很好! django的模板太tmd的弱了 呵呵,其实我倒是对django的模板没太大意见,弱也有弱的好处吧。 |
|
返回顶楼 | |
发表时间:2009-03-01
推荐一下我最近再搞的一个跨平台的模板引擎吧,目前可以支持Java,JS,Python和php。
但是后两者没怎么用过,也缺乏充分测试。 JS版本在线测试: http://www.xidea.org/project/lite/ GoogleCode: http://lite.googlecode.com/ 不过楼主期待的直接调用原生代码,肯定是不能支持的,不过如果不喜欢目前的语法风格,也可以编写自己的语法解析器,Lite是基于中间代码的,你编写的扩展,同样可以跨平台。 |
|
返回顶楼 | |
发表时间:2009-03-01
我都没用过这个 是不是很落伍呢
|
|
返回顶楼 | |
发表时间:2009-03-01
django的模板我用的是mako,django自己的模板是很弱。虽然感觉很优雅,但不实用。
|
|
返回顶楼 | |
发表时间:2009-03-03
有没有人比较过各个模板,那个性能较高?
|
|
返回顶楼 | |
发表时间:2009-04-27
guotie 写道 有没有人比较过各个模板,那个性能较高?
Django自己的模板性能是非常低的。 Lite的实现都比他高四倍,而且Lite现在的版本还有非常大的优化空间。 |
|
返回顶楼 | |
发表时间:2009-05-15
感谢!
顺着jinja2来到了这里 http://dev.pocoo.org/ 真是强大的team,产出的都是精品。 ps: 我很喜欢写filter ;-) |
|
返回顶楼 | |
浏览 11282 次