Django模板标签:在满足条件的for循环的第一个元素上设置.active

时间:2012-09-17 11:27:33

标签: django for-loop django-templates

我遇到以下问题:用户正在我的网站上学习课程。课程由几个章节组成,每章包含几个步骤。如果用户已登录并完成步骤,则后端将保存进度。当用户回到网站时,我希望他继续他离开的地方。为此,我必须将css类“active”添加到相应的导航步骤和每章的内容选项卡。我的出发点是如果用户已完成该步骤,则使用if语句进行测试。这很有效,但是对所有尚未完成的步骤添加.active。我只想将它添加到尚未完成的第一步。我实际上已经解决了这个问题,但它是一个相当粗暴的黑客,我不得不包括custom template tag that allows me to set a variable in the template

{% load custom_tags %}

{% for chapter in chapters %}
<div>
    <ul class="unstyled wizard clearfix">
        {% set active_wizard_steps = 0 %}
        {% for step in chapter.steps.all %}
        <li class="{% if not step.read and active_wizard_steps == 0 %}active{% set active_wizard_steps = 1 %}{% endif %}{% if step.read %} finished{% endif %}"></li>
        {% endfor %}
    </ul>
</div>
{% endfor %}

我知道这也可以通过将列表或字典传递给包含所有活动步骤的模板,然后在模板中测试步骤是否在该列表中来完成。但这意味着重写了很多视图代码,所以我决定在模板中完成它。

所以我的问题是:解决这个问题的最佳做法是什么?我只是出于好奇而问,因为这个问题实际上很有趣。非常感谢!

2 个答案:

答案 0 :(得分:2)

向Step:

添加方法
class Step(models.Model):
    # ...
    def is_active(self):
        # do your sauce

在模板中:

class="{% if step.is_active %}active{% endif %}"

我们在模型中已经有像get_absolute_url这样的方便助手,为什么不添加这个呢?

如果你不喜欢它,你可以做一个模板过滤器并按原样使用它:

class="{% if step|is_active %}active{% endif %}"

更新

这是另一种方法,如下所示制作模板过滤器:

@register.filter
def set_active_steps(steps):
    active_wizard_steps = 0

    for step in steps:
        if not step.read and active_wizard_steps == 0:
            step.is_active = True

    return steps

然后,在您的模板中:

{% for step in chapter.steps.all|set_active_steps %}
    ... {% if step.is_active %}...{% endif %}
{% endfor %}

答案 1 :(得分:0)

我知道你已经解决了你的问题,我为了完成而发布了另一个答案。

如果您需要在{% for %}{% endfor %}内部通过将当前向导步骤与循环中的当前项匹配来设置类,则可以使用以下代码:

{% for step in wizard.steps.all %}
    <li class="{% if wizard.steps.step1 == forloop.counter %}active{% elif wizard.steps.step1 > forloop.counter %} complete{% endif %}">
          <span class="step">{{ forloop.counter }}</span>
    </li>
 {% endfor %}