如何重复Django模板中的“块”

我想在同一个Django模板中使用相同的{%block%}两次。 我希望这个块在我的基本模板中出现多次:

# base.html <html> <head> <title>{% block title %}My Cool Website{% endblock %}</title> </head> <body> <h1>{% block title %}My Cool Website{% endblock %}</h1> </body> </html> 

然后扩展它:

 # blog.html {% extends 'base.html' %} {% block title %}My Blog{% endblock %} # pictures.html {% extends 'base.html' %} {% block title %}My Pictures{% endblock %} # cats.html {% extends 'base.html' %} {% block title %}My Cats{% endblock %} 

我会得到一个exception,因为Django希望块只出现一次:

TemplateSyntaxError at /

名称为“标题”的“块”标记会多次出现

一个快速和肮脏的解决scheme将重复块标题title1title2

 # blog.html {% extends 'base.html' %} {% block title1 %}My Blog{% endblock %} {% block title2 %}My Blog{% endblock %} 

但是这违反了DRY原则。 这将是非常困难的,因为我有很多inheritance模板,也因为我不想下地狱;-)

这个问题有什么窍门或解决办法吗? 我如何重复我的模板中的同一个块,而不重复所有的代码?

我认为使用上下文处理器在这种情况下是一种矫枉过正。 你可以轻松做到:

 #base.html <html> <head> <title>{% block title %}My Cool Website{% endblock %}</title> </head> <body> {% block content %}{% endblock %} </body> </html> 

接着:

 # blog.html {% extends 'base.html' %} {% block content %} <h1>{% block title %}My Blog{% endblock %}</h1> Lorem ipsum here... {% endblock %} 

等等…看起来像DRY兼容。

使用Django模板macros插件:

http://www.djangosnippets.org/snippets/363/(django <1.4)

要么

https://gist.github.com/1715202 (django> = 1.4)

然后,

 # base.html {% macro title %} {% block title %}My Cool Website{% endblock %} {% endmacro %} <html> <head> <title>{% usemacro title %}</title> </head> <body> <h1>{% usemacro title %}</h1> </body> </html> 

 # blog.html {% extends 'base.html' %} {% block title %}My Blog{% endblock %} 

你可能实际上不想使用一个块,而只是使用一个variables:

 # base.html <html> <head> <title>{{ title|default:"My Cool Website" }}</title> </head> <body> <h1>{{ title|default:"My Cool Website" }}</h1> </body> </html> 

然后您通过上下文设置标题。

你可以多次使用{% include subtemplate.html %} 。 它不是一样的块,但伎俩。

以下是我自己尝试做同样的事情时发现的一种方法:

 # base_helper.html <html> <head> <title>{% block _title1 %}{% endblock %}</title> </head> <body> <h1>{% block _title2 %}{% endblock %}</h1> </body> </html> # base.html {% extends "base_helper.html" %} # Copy title into _title1 & _title2, using "My Cool Website" as a default. {% block _title1 %}{% block _title2 %}{% block title %}My Cool Website{% endblock %}{% endblock %}{% endblock %} 

不幸的是需要额外的文件,但不要求你从视图中传递标题。

这里有一些讨论: http : //code.djangoproject.com/ticket/4529很明显,Django核心团队拒绝这张票,因为他们认为这不是一个常用的场景,但我不同意。

重复块是简单和干净的实现这个: https : //github.com/SmileyChris/django-repeatblock

模板macros是另一个,但作者提到它没有仔细testing: http : //www.djangosnippets.org/snippets/363/

我使用重复块。

基于Van Gale的build议,您可以通过将以下内容添加到您的templatetags.py文件中来创buildget和set标签:

 register = template.Library() Stateful = {} def do_set(parser, token): _, key = token.split_contents() nodelist = parser.parse(('endset',)) parser.delete_first_token() # from the example -- why? return SetStatefulNode(key,nodelist) class SetStatefulNode(template.Node): def __init__(self, key, nodes): Stateful[key] = nodes def render(self, context): return '' register.tag('set', do_set) def do_get(parser, token): tag_name, key = token.split_contents() return GetStatefulNode(key) class GetStatefulNode(template.Node): def __init__(self, key): self.key = key def render(self, context): return ''.join( [x.render(context) for x in Stateful[self.key]] ) register.tag('get', do_get) 

然后通过{% set foo %}put data here{% endset %}在一个模板中设置值,并通过{% get foo %}在另一个模板中{% get foo %}

这是一个类似于上面的do_setdo_get模板标签答案的轻量级解决scheme。 Django允许你将整个模板上下文传递给一个标签,它可以让你定义一个全局variables。

base.html文件:

 <!DOCTYPE html> <html lang="en"> <head> {% block head %} <title>{{ title }}</title> {% endblock %} </head> <body> <h1>{{ title }}</h1> </body> </html> 

page.html中:

 {% extends "base.html" %} {% block head %} {% define 'title' 'Homepage | title' %} {{ block.super }} {% endblock %} 

自定义标记(在这里得到了这个主意: https : //stackoverflow.com/a/33564990/2747924 ):

 @register.simple_tag(takes_context=True) def define(context, key, value): context.dicts[0][key] = value return '' 

另外,不要忘记{% load %}您的自定义标签或将它们添加到模板选项builtins列表,所以你不必在每个模板中加载它们。 这种方法的唯一限制是必须从块标记中调用{% define %} ,因为子模板只会呈现与父标记匹配的块标记。 不知道是否有办法。 还要确保在你尝试define地使用define call之前。

我也遇到了在我的模板文件中重复{%block%}的相同需求。 问题是,我想要在Django条件下使用Django {%block%},并且希望{%block%}能被可能扩展当前文件的后续文件覆盖。 (所以在这种情况下,我想要的肯定比块variables更块,因为我没有在技术上重用它,它只出现在条件的任一端。

问题:

下面的Django模板代码将导致模板语法错误,但我认为这是一个有效的“希望”有一个定义的{%block%}重复使用的条件(IE中,为什么Django语法分析器validation语法结束有条件的,不应该只validationTRUTHY条件?)

 # This example shows a {{ DEBUG }} conditional that loads # Uncompressed JavaScript files if TRUE # and loads Asynchronous minified JavaScript files if FALSE. # BASE.html {% if DEBUG %} <script src="{{MEDIA_URL}}js/flatfile.1.js"></script> <script src="{{MEDIA_URL}}js/flatfile.2.js"></script> <script src="{{MEDIA_URL}}js/flatfile.3.js"></script> <script type="text/javascript"> {% block page_js %} var page = new $site.Page(); {% endblock page_js %} </script> {% else %} <script type="text/javascript"> // load in the PRODUCTION VERSION of the site // minified and asynchronosly loaded yepnope([ { load : '{MEDIA_URL}}js/flatfiles.min.js', wait : true, complete : function() { {% block page_js %} // NOTE THE PAGE_JS BLOCK var page = new $site.Page(); {% endblock page_js %} } } )]; </script> {% endif %} # ABOUT.html {% extends 'pages/base.html' %} {% block page_js %} var page = new $site.Page.About(); {% endblock page_js %} 

解决scheme:

您可以使用{%include%}多次有条件地插入{%block%}。 这对我有用,因为Django语法检查器只包含TRUTHY {%include%}。 看到下面的结果:

 # partials/page.js {% block page_js %} var page = new $site.Page(); {% endblock %} # base.html {% if DEBUG %} <script src="{{MEDIA_URL}}js/flatfile.1.js"></script> <script src="{{MEDIA_URL}}js/flatfile.2.js"></script> <script src="{{MEDIA_URL}}js/flatfile.3.js"></script> <script type="text/javascript"> {% include 'partials/page_js.html' %} </script> {% else %} <script type="text/javascript"> yepnope([ { load : '{MEDIA_URL}}js/flatfiles.min.js', wait : true, complete : function() { {% include 'partials/page_js.html' %} } } )]; </script> {% endif %} 

作为任何人的更新,我已经把上面提到的代码片段变成了一个模板标签库django-macros,这使得macros更强大,并且明确地实现了一个重复的块模式: django-macros 。

有两个简单的解决scheme。

最简单的是把你的标题放到一个上下文variables中。 你可以在你的视图中设置上下文variables。

如果您使用的是像通用视图的东西,并没有一个views.py的图片,猫等,那么你可以去一个自定义模板标签,在上下文中设置一个variables的方式 。

走这条路线可以让你做这样的事情:

 {% extends "base.html" %} {% load set_page_title %} {% page_title "My Pictures" %} ... 

然后在你的base.html中:

 ... {% block title %}{{ page_title }}{% endblock %} ... <h1>{{ page_title }}</h1> 

我用这个答案来保持干燥。

 {% extends "base.html" %} {% with "Entry Title" as title %} {% block title %}{{ title }}{% endblock %} {% block h1 %}{{ title }}{% endblock %} {% endwith %} 

在树枝上,你可以这样做:

 # base.html <html> <head> <title>{{ block('title') }}</title> </head> <body> <h1>{{ block('title') }}</h1> </body> </html> # blog.html {% extends 'base.html' %} {% block title %}My Blog{% endblock %} # pictures.html {% extends 'base.html' %} {% block title %}My Pictures{% endblock %} # cats.html {% extends 'base.html' %} {% block title %}My Cats{% endblock %}