【发布时间】:2011-09-07 04:31:24
【问题描述】:
在将模板包含在 Django 模板中之前,是否有一种开箱即用的方法来检查模板是否存在?也欢迎其他替代方案,但由于特定情况,其中一些将不起作用。
例如,这里有一个稍微不同的问题的答案。这不是我要找的: How to check if a template exists in Django?
【问题讨论】:
标签: django templates try-catch exists
在将模板包含在 Django 模板中之前,是否有一种开箱即用的方法来检查模板是否存在?也欢迎其他替代方案,但由于特定情况,其中一些将不起作用。
例如,这里有一个稍微不同的问题的答案。这不是我要找的: How to check if a template exists in Django?
【问题讨论】:
标签: django templates try-catch exists
如果模板存在,我需要有条件地包含模板,但我想使用一个变量来存储模板名称,就像您可以使用常规 {% include %} 标记一样。
这是我在 Django 1.7 中使用的解决方案:
from django import template
from django.template.loader_tags import do_include
register = template.Library()
class TryIncludeNode(template.Node):
"""
A Node that instantiates an IncludeNode but wraps its render() in a
try/except in case the template doesn't exist.
"""
def __init__(self, parser, token):
self.include_node = do_include(parser, token)
def render(self, context):
try:
return self.include_node.render(context)
except template.TemplateDoesNotExist:
return ''
@register.tag('try_include')
def try_include(parser, token):
"""
Include the specified template but only if it exists.
"""
return TryIncludeNode(parser, token)
在 Django 模板中,它可以这样使用:
{% try_include "template-that-might-not-exist.html" %}
或者,如果模板名称位于名为 template_name 的变量中:
{% try_include template_name %}
【讨论】:
parser 和 token 被传递给模板标签,@register.tag('try_include') 装饰器将其注册为模板标签...我将添加一个在模板中使用它的示例: )
我在尝试仅在模板存在时才显示模板时遇到了这种情况,并最终使用了以下模板标记解决方案:
将以下内容放入yourapp/templatetags/include_maybe.py
from django import template
from django.template.loader_tags import do_include
from django.template.defaulttags import CommentNode
register = template.Library()
@register.tag('include_maybe')
def do_include_maybe(parser, token):
"Source: http://stackoverflow.com/a/18951166/15690"
bits = token.split_contents()
if len(bits) < 2:
raise template.TemplateSyntaxError(
"%r tag takes at least one argument: "
"the name of the template to be included." % bits[0])
try:
silent_node = do_include(parser, token)
except template.TemplateDoesNotExist:
# Django < 1.7
return CommentNode()
_orig_render = silent_node.render
def wrapped_render(*args, **kwargs):
try:
return _orig_render(*args, **kwargs)
except template.TemplateDoesNotExist:
return CommentNode()
silent_node.render = wrapped_render
return silent_node
通过在模板顶部添加 {% load include_maybe %} 并在代码中使用 {% include_maybe "my_template_name.html" %} 从模板中访问它。
这种方法具有很好的副作用,即搭载现有的模板包含标记,因此您可以像使用普通的{% include %} 一样传递上下文变量。
但是,如果模板存在,我希望在嵌入站点上进行一些额外的格式设置。我没有编写{% if_template_exists %} 标签,而是编写了一个过滤器,让您可以使用现有的{% if %} 标签。
为此,将以下内容放入yourapp/templatetags/include_maybe.py(或其他内容)
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
@register.filter
@stringfilter
def template_exists(value):
try:
template.loader.get_template(value)
return True
except template.TemplateDoesNotExist:
return False
然后,从您的模板中,您可以执行以下操作:
{% load include_maybe %}
{% if "my_template_name"|template_exists %}
<div>
<h1>Notice!</h1>
<div class="included">
{% include_maybe "my_template_name" %}
</div>
</div>
{% endif %}
与使用自定义标签相比,使用自定义过滤器的优势在于您可以执行以下操作:
{% if "my_template_name"|template_exists and user.is_authenticated %}...{% endif %}
而不是使用多个{% if %} 标签。
请注意,您仍然必须使用include_maybe。
【讨论】:
do_include_maybe 停止使用 Django 1.7 (traceback)。似乎现在稍后会抛出异常,而不是来自do_include。我已经在上面修复了它,总是尝试获取模板。
include_maybe。
template.loader.get_template位吗?如果你只是做return do_include(parser, token),那么它本身不应该抛出一个 TemplateDoesNotExist 异常吗?
bits[1] 时也是如此,这似乎更正确。我将更新似乎适用于 Django 1.7 和希望旧版本的代码。
假设 include 不会在你传递一个错误的模板引用时崩溃,这可能是最好的方法。您的另一种选择是创建一个模板标记,该标记基本上在您提到的链接中进行检查。
非常基本的实现:
from django import template
register = template.Library()
@register.simple_tag
def template_exists(template_name):
try:
django.template.loader.get_template(template_name)
return "Template exists"
except template.TemplateDoesNotExist:
return "Template doesn't exist"
在您的模板中:
{% template_exists 'someapp/sometemplate.html' %}
那个标签并不是真的那么有用,所以你可能想要创建一个实际上将一个变量添加到上下文中的标签,然后你可以检查一个 if 语句或其他什么。
【讨论】:
【讨论】:
include 包装起来以检查变量。但当然这并不理想,如您所建议的那样,使用专用标签可能会更好。