【问题标题】:Django: Passing argument to parent templateDjango:将参数传递给父模板
【发布时间】:2010-12-26 00:01:01
【问题描述】:

我有这种风格的模板

project
- main_templates (including nav bar)
-- app1
--- app1_base_template
--- app1_templates
-- app2
--- app2_base_template
--- app2_templates

所以在渲染时,app2_templates 扩展了 app2_base_template,它扩展了 main_template。

我需要做的是,在渲染 app2 的模板时,让相应的导航项加粗(向用户显示他在哪里)。

如果我可以在 {% block xxx %} 部分中传递一个变量,那么最简单的方法就是。 这可能吗?

还有哪些通用方法?

【问题讨论】:

标签: django django-templates


【解决方案1】:

你试过 {% with %} 模板标签吗?

{% block content %}
  {% with 'myvar' as expectedVarName %}
  {{block.super}}
  {% endwith %}
{% endblock content %}

【讨论】:

  • 很抱歉,我不明白这一点。这是在 base.html 中,block.super 是指导航栏...?我的导航栏包含在我的基础中,然后我的block content...应该如何设置它才能工作?
  • 有趣的 hack 但不是完整的解决方案。父模板大部分需要用{% block content %} 包围才能正常工作,这可以防止我覆盖content 内的其他块。
  • 在 Django 1.11+ 中语法发生了变化,即使旧的仍然支持:docs.djangoproject.com/en/1.11/ref/templates/builtins/#with .{% with 'myvar' as expectedVarName %} => {% with expectedVarName ='myvar' % }
【解决方案2】:

没有直接的方法可以按照您描述的方式将变量向上传递到模板继承树。人们实现突出显示当前页面的导航栏的方式通常会根据网站本身的性质进行调整。也就是说,我看到了两种常见的方法:

低技术方法

在模板上下文中传递一个变量来指示哪个选项卡处于活动状态:

# in views.py
def my_view(request):
    return render_to_response('app2_template.html', {"active_tab": "bar"},

<!-- Parent template -->
<div id="navigation">
    <a href="/foo" {% ifequal active_tab "foo" %}class="active"{% endifequal %}>Foo</a>
    <a href="/bar" {% ifequal active_tab "bar" %}class="active"{% endifequal %}>Bar</a>
</div>

高科技方法

实现custom template tag 来呈现您的导航栏。让标签采用一个变量来指示哪个部分处于活动状态:

<!-- Parent template -->

<div id="navigation">{% block mainnav %}{% endblock %}</div>

<!-- any child template -->
{% load my_custom_nav_tag %}
{% block mainnav %}{% my_custom_nav_tag "tab_that_is_active" %}{% endblock %}

你几乎可以从那里发疯。你可能会发现有人已经在 djangosn-ps.org 上实现了一些对你有用的东西。

【讨论】:

  • +1 表示高科技方法。我进行了一些研究以使其正常工作,并详细说明了将哪些文件放在哪里可以在将来对某些人有所帮助的参考。
【解决方案3】:

无法在模板包含中传递参数是 Django 模板系统的众多失败之一。

我不得不处理一个几乎相同的问题:深度嵌套的模板需要使父模板以不同的方式格式化/突出显示。

可能的解决方案:

  1. 使用“超级上下文”例程,根据您在层次结构中的位置设置多个值。 IE。 super_context = MySuperContext(request, other, values, etc.),其中 super_context 是您传递给视图(或 RequestContext)的字典。这是最 Django-thnonic(?) 的方法,但这意味着表示逻辑已被推回到视图中,这让我感觉不对。

  2. 使用expr 模板标签在较低级别的模板中设置值。注意:这仅在您 {% include %} 模板时有效,因为必须在包含发生之前对其进行评估。您不能使用 {% extends %} 来做到这一点,因为这必须是子模板中的第一件事。

  3. 切换到Jinja2 模板,至少对于您需要这样做的视图。

一旦您设置了这些值,您就可以执行以下操作:

<div class="foo{% if foo_active%}_active{%endif%}"> stuff </div>

这使得 div 类在不活动时为“foo”,当它处于活动状态时为“foo_active”。根据口味调整风格,但不要添加太多肉桂。 :-)

【讨论】:

    【解决方案4】:

    我在类似的错误...上下文中采用了 Jarret Hardie 的“低技术”方法(是的,这是一个双关语...除非我告诉您我没有做导航,否则这对您来说并不完全合理但是设置按钮的边框颜色以显示哪个按钮被按下)。

    但我认为我的版本更紧凑一些。我不是在视图中只定义一个简单的上下文变量 activebar,而是返回一个字典,但总是只有一个键值对:例如活动栏 = {'foo': '活动'}。

    然后在模板中,我只需将 class="{{activebar.foo}}" 写入 foo 锚点,并相应地写入其他锚点。如果仅将 activebar.foo 定义为具有值“active”,则 bar 锚中的 activebar.bar 将不执行任何操作。也许“默默地失败”是正确的 Django 谈话。 Bob 是你的叔叔。

    编辑:哎呀...几天过去了,虽然我上面写的确实对我有用,但当我将一个以新窗口作为目标的锚点放入导航栏中时,出现了一个问题。这似乎是一个奇怪故障的原因:在单击新窗口(Firefox 中的选项卡)然后返回到启动新窗口的窗口后,每当我快速移动将光标悬停在导航栏上的项目上---无需单击任何内容。我不得不通过移动滚动条来强制重绘屏幕(不是重新加载页面,尽管这也很有效,因为它涉及屏幕重绘)。

    我太菜鸟了,无法弄清楚为什么会发生这种情况。有可能我做了其他事情导致问题以某种方式消失了。但是......我找到了一种更简单的方法,对我来说非常有效。我的情况是,从视图启动的每个子模板都应该导致关联的导航栏项目显示为“活动”。事实上,导航栏项目是启动子模板的视图的那个项目——通常的交易。

    我的解决方案---让我们以“登录”导航栏项目为例---是将其放在包含登录表单的子模板中。

    {% block login %}active{% endblock %}
    

    我把它放在标题栏下方,但我认为放置位置并不重要。然后在包含导航栏定义的父模板中,对于围绕我放置的登录导航栏项目的锚点的 li 标记......好吧,这是代码:

    <li class="{% block login %}{% endblock %}"><a href="/mysite/login">Login</a></li>
    

    因此,当渲染子模板时,父模板会将登录导航栏项显示为活动的,并且 Bob 仍然是你的叔叔。

    我上面描述的字典方法是显示一行按钮中的哪一个被按下,当它们都在同一个子模板上​​时。这仍然对我有用,因为只涉及一个子模板,我看不出我的导航栏新方法在这种情况下如何工作。请注意,使用导航栏视图的新方法甚至不涉及。更简单!

    【讨论】:

      【解决方案5】:

      来自父模板的变量会自动包含在子模板的作用域中。您的标题说您想将变量传递给父级,这没有意义,因为您无法在模板中定义变量。如果您需要它在父子节点中的变量,只需在视图中声明它。

      【讨论】:

      • 这个问题确实有道理。 Django 模板系统,也许没有。
      【解决方案6】:

      遗憾的是我找不到干净的方法。

      最终在每个应用的 base.html 中添加了一个标签:

      <span class="main_nav_bar_hint" id="2"></span>
      

      (其实我用了两个。一个由应用程序的基础设置为主导航。一个由应用程序页面设置为应用程序的导航栏)

      在项目 base.html 中还有一点 JQuery 的魔力

      $(document).ready(function() { $("#nav_menu_" + $(".main_nav_bar_hint").attr("id")).removeClass("normal").addClass("selected"); })
      

      这有点小技巧,但这种方式很容易理解,我只需要在添加更多应用后进行逻辑更改。

      【讨论】:

        【解决方案7】:

        您可以使用 HttpRequest.resolver_match。

        在父 html 模板中:

        <li class="nav-item {% if request.resolver_match.view_name == 'my_simple_blog:homepage' %}active{% endif %}"><a href="{% url 'my_simple_blog:homepage' %}" class="nav-link">Home</a></li>
        <li class="nav-item {% if request.resolver_match.view_name == 'my_simple_blog:about' %}active{% endif %}"><a href="{% url 'my_simple_blog:about' %}" class="nav-link">About</a></li>
        

        它检查当前命名空间并进行比较,如果它们相同,则在列表的类中添加active。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2015-09-22
          • 1970-01-01
          • 2011-07-03
          • 2021-06-05
          • 2016-06-29
          • 1970-01-01
          相关资源
          最近更新 更多