Django:将参数传递给父模板

时间:2009-12-12 14:28:47

标签: django django-templates

我有这种风格的模板

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

因此,在渲染时,app2_templates扩展了扩展main_template的app2_base_template。

我需要做的是,在渲染app2的模板时将相应的导航项设为粗体(向用户显示他所在的位置)。

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

还有哪些其他通用方法?

7 个答案:

答案 0 :(得分:42)

您是否尝试过{%with%}模板标记?

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

答案 1 :(得分:9)

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

低技术方法

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

# 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 %}

你可以从那里疯狂。你可能会发现有人已经在djangosnippets.org上实现了适合你的东西。

答案 2 :(得分:2)

父模板中的变量会自动包含在子项的范围内。您的标题表示您要将变量传递给父级,这没有意义,因为您无法在模板中定义变量。如果您需要父和子中的变量,只需在视图中声明它。

答案 3 :(得分:2)

无法在模板包含上传递args是Django模板系统的许多失败之一。

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

可能的解决方案:

  1. 使用“超级上下文”例程,根据您所在的层次结构中的位置设置多个值。即super_context = MySuperContext(请求,其他,值等),其中super_context是传递给视图(或RequestContext)的字典。这是最Django-thnonic(?)方法,但这意味着表示逻辑已被推回到视图中,这对我来说是错误的。

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

  3. 切换到Jinja2模板,至少对于您需要执行此操作的视图。

  4. 设置这些值后,您可以执行以下操作:

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

    这使得div类在它不活动时为“foo”而在它是时为“foo_active”。风味,但不要添加太多肉桂。 : - )

答案 4 :(得分:2)

我采用了Jarret Hardie的“低技术”方法,在类似的,错误的......背景下(是的,这是一个双关语...除非我告诉你我没有做导航,否则对你来说不会有任何意义但设置按钮的边框颜色以显示已按下哪个按钮。

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

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

编辑:哎呀......几天过去了,虽然我上面写的内容确实对我有用但是当我把一个新窗口作为目标放入导航栏时出现问题。这似乎是一个奇怪的故障的原因:点击新窗口(Firefox中的选项卡)然后返回到启动新窗口的窗口,导航栏下方的部分显示变为空白,只要我快速移动光标在导航栏上的项目上---没有点击任何东西。我不得不通过移动滚动条强制屏幕重绘(不是页面重新加载,虽然它太有效,因为它涉及屏幕重绘)。

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

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

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

我把它放在标题栏下面,但我不认为这个位置很重要。然后在包含导航栏定义的父模板中,对于我所放置的登录导航栏项目的锚点周围的li标签...嗯,这是代码:

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

因此,当渲染子模板时,父模板会将登录导航栏项目显示为活动状态,而Bob仍然是您的叔叔。

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

答案 5 :(得分:1)

可悲的是,我找不到干净的方式。

结束在每个应用的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"); })

它有点像黑客,但这种方式很容易理解,我只需要在添加更多应用程序后进行逻辑更改。

答案 6 :(得分:-1)

您可以使用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。