【问题标题】:Check if a template exists within a Django template检查 Django 模板中是否存在模板
【发布时间】:2011-09-07 04:31:24
【问题描述】:

在将模板包含在 Django 模板中之前,是否有一种开箱即用的方法来检查模板是否存在?也欢迎其他替代方案,但由于特定情况,其中一些将不起作用。

例如,这里有一个稍微不同的问题的答案。这不是我要找的: How to check if a template exists in Django?

【问题讨论】:

    标签: django templates try-catch exists


    【解决方案1】:

    如果模板存在,我需要有条件地包含模板,但我想使用一个变量来存储模板名称,就像您可以使用常规 {% 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 %}
    

    【讨论】:

    • 在 2+ 中也能像魅力一样工作!
    • 一个使用中的例子(例如什么是解析器和令牌)会很有用。
    • @BerndWechner parsertoken 被传递给模板标签,@register.tag('try_include') 装饰器将其注册为模板标签...我将添加一个在模板中使用它的示例: )
    【解决方案2】:

    我在尝试仅在模板存在时才显示模板时遇到了这种情况,并最终使用了以下模板标记解决方案:

    仅当模板存在时才包含模板

    将以下内容放入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。我已经在上面修复了它,总是尝试获取模板。
    • +1 嘿,我刚打电话给你,这太疯狂了,但这是我的模板,所以include_maybe
    • 你必须做template.loader.get_template位吗?如果你只是做return do_include(parser, token),那么它本身不应该抛出一个 TemplateDoesNotExist 异常吗?
    • @Lochlan 可能!尽管它实际上也会继续执行该模板,但这可能会很慢。
    • @Lochlan 额外的调用是为 Django 1.7 准备的,但它似乎也停止了在那里工作——在使用 bits[1] 时也是如此,这似乎更正确。我将更新似乎适用于 Django 1.7 和希望旧版本的代码。
    【解决方案3】:

    假设 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 语句或其他什么。

    【讨论】:

      【解决方案4】:

      include 接受变量:

      {% include template_name %}
      

      这样您就可以在视图中进行检查。

      【讨论】:

      • 如果模板不存在,这不会引发 TemplateDoesNotExist 异常吗?
      • 好的,我的意思是仅当模板存在时才传递模板变量(并在视图中捕获潜在的异常)。这样一来,人们就可以轻松地将include 包装起来以检查变量。但当然这并不理想,如您所建议的那样,使用专用标签可能会更好。
      猜你喜欢
      • 2011-11-20
      • 1970-01-01
      • 2021-07-02
      • 2019-09-01
      • 2021-02-26
      • 1970-01-01
      • 2019-07-05
      • 2013-06-07
      • 1970-01-01
      相关资源
      最近更新 更多