【问题标题】:Django include template tag in for loop only catches first iterationDjango 在 for 循环中包含模板标记仅捕获第一次迭代
【发布时间】:2016-07-07 16:12:00
【问题描述】:

我在我网站的某些页面上有一个 cmets 部分,我使用 {% for ... %} 循环(以及另一个用于评论回复的嵌套循环)构建了一个 cmets 部分。该部分被一起破解,我仍在学习 Web 开发和 Django,所以请原谅任何令人沮丧的草率或怪异。我现在不关心效率,只关心效率,现在它工作得不太对。

对于每条评论,我都有一个 Bootstrap 下拉按钮,它将显示选项 EditDeleteEdit 将打开一个模式来编辑评论。模态框使用{% include %} 标签呈现。下面我包含了部分未修改的代码,而不是试图简化我的示例并冒着遗漏一些重要内容的风险:

<div class="panel panel-default">
    {% for comment in spot.ordered_comments %}
    <div class="panel-heading row">
        <div class="col-sm-10">
            <strong>{{ comment.poster.username }}</strong>
            <em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
        </div>
        <div class="btn-group col-sm-2" role="group">

            {% if comment.poster == user %}
            <form id="delete-comment-form" class="form"
                  method="post" action="{% url 'delete_comment' spot.id comment.id %}">
                {% csrf_token %}
            </form>

            {% include 'topspots/editmodal.html' with edit_type='comment' %}

            <div class="btn-group">
                <button type="button" class="btn btn-default dropdown-toggle"
                        data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                    <i class="fa fa-edit"></i> <span class="caret"></span>
                </button>
                <ul class="dropdown-menu">
                    <li><a href="#" data-toggle="modal" data-target="#editModal">Edit</a></li>
                    <li role="separator" class="divider"></li>
                    <li>
                        <a href="javascript:;" onclick="$('#delete-comment-form').submit();">Delete</a>
                    </li>
                </ul>
            </div>

            {% endif %}

            {% if user.is_authenticated %}
            {% include 'topspots/replymodal.html' %}
            <button type="button" class="btn btn-default" data-toggle="modal"
                    data-target="#replyModal">
                Reply
            </button>
            {% endif %}
        </div>
    </div>

    <div class="panel-body">
        <div class ="row">
            <div class="col-sm-8">
                {{ comment.comment_text }}
            </div>
        </div>
        <br/>

        <!-- Comment replies -->
        {% if comment.commentreply_set %}
        {% for reply in comment.commentreply_set.all %}
        <div class="row" style="padding-left: 1em">
            <div class="col-sm-8 well">
                <p>{{ reply.reply_text }}</p>
                <div class="row">
                    <div class="col-sm-4">
                        <p>
                            <strong>{{ reply.poster.username }}</strong>
                            <em style="margin-left: 2em">{{ comment.created|date:'M d \'y \a\t H:i' }}</em>
                        </p>
                    </div>
                    {% if reply.poster == user %}
                    {% include 'topspots/editmodal.html' with edit_type='reply' %}
                    <form id="delete-reply-form" class="form"
                          method="post" action="{% url 'delete_reply' spot.id reply.id %}">
                        {% csrf_token %}
                    </form>
                    <div class="col-sm-2">
                        <div class="btn-group">
                            <button type="button" class="btn btn-default dropdown-toggle"
                                    data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                <i class="fa fa-edit"></i> <span class="caret"></span>
                            </button>
                            <ul class="dropdown-menu">
                                <li><a href="#" data-toggle="modal"
                                       data-target="#editModal">Edit</a></li>
                                <li role="separator" class="divider"></li>
                                <li>
                                    <a href="javascript:;"
                                       onclick="$('#delete-reply-form').submit();">Delete</a>
                                </li>
                            </ul>
                        </div>
                    </div>
                    {% endif %}
                </div>
            </div>
        </div>
        {% endfor %}
        {% endif %}

    </div>
    {% endfor %}
</div>

这里是编辑模式:

<!-- editmodal.html -->
{% load static %}

<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span></button>
                <h2 class="modal-title" id="editModalLabel">
                    Edit {{ edit_type }}:
                </h2>
            </div>
            <form action="{% url 'edit_comment' spot.id comment.id %}" method="post">
                <div class="modal-body">
                    <input class="form-control" name="text" value="{{ comment.comment_text }}" autofocus>
                    <input type="hidden" name="edit_type" value="{{ edit_type }}">
                    {% csrf_token %}
                </div>
                <div class="modal-footer">
                        <button type="submit" class="btn btn-default">Finish editing</button>
                </div>
            </form>
        </div>
    </div>
</div>
<script>

    $('.modal').on('shown.bs.modal', function() {
        $(this).find('[autofocus]').focus();
    });

</script>

以及回复模式:

<!-- replymodal.html -->
{% load static %}

<div class="modal fade" id="replyModal" tabindex="-1" role="dialog" aria-labelledby="replyModalLabel">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span></button>
                <h2 class="modal-title" id="replyModaLabel">
                    Reply to <strong>{{ comment.poster.username }}'s</strong> comment
                </h2>
            </div>
            <div class="modal-body">
                <form action="{% url 'reply_comment' spot.id comment.id %}" method="post">
                    <input class="form-control" name="reply_text" placeholder="Write a reply..." autofocus>
                    {% csrf_token %}
                </form>
            </div>
        </div>
    </div>
</div>
<script>

    $('.modal').on('shown.bs.modal', function() {
        $(this).find('[autofocus]').focus();
    });

</script>

我遇到的问题是我的回复和编辑模式(例如 {% include 'topspots/editmodal.html' with edit_type='reply' %}{% include 'topspots/replymodal.html' %} 似乎只在我的 for 循环的第一次迭代的上下文中呈现一次。所以即使所有问题都是正确的呈现在页面上,当我点击回复、编辑或删除时,无论我点击哪个按钮(即我点击第一条评论的按钮,还是第五条评论的按钮等),我都只能回复、编辑或删除第一条评论。我觉得这与闭包和范围有关,我不太理解(过去我在 Python 循环中使用 lambda 时遇到了意外结果,因为 @ 987654321@ 或 this),但我不确定。

我用以下视图做了一个测试:

def test(request):
    spots = Spot.objects.all()
    return render(request, 'test.html', {'spots': spots})

和模板:

<!-- test.html -->
<h1>Hello world</h1>
{% for spot in spots %}
    {% include 'testinclude.html' %}
{% endfor %}

<!-- testinclude.html -->
<h3>{{ spot.name }}</h3>

它打印出一个独特的点名称列表,那么为什么与模态有区别呢?

【问题讨论】:

  • 您正在为模态元素重用 id。我的猜测是模板按照您的预期呈现,但 javascript 只打开第一个模式。

标签: python django loops django-templates closures


【解决方案1】:

作为emulbreh postulates,实际上每条评论都会呈现一个模式。但是,所有的模态框都有相同的 ID,所以无论点击哪个评论的编辑按钮,每次都会触发第一个模态框。 ID 在 HTML 文档中应该是唯一的。

你怎么能解决这个问题?您可以使模式的 ID 对每个评论都是唯一的。您可以通过编写 id="editModal-{{ comment.id }}" 或只是 id="editModal-{{ forloop.counter }}(文档 here)来获得唯一标识符。

但是你的editModal.html 模板与你的“主”模板非常紧密地耦合在一起。更好的解决方案是使用classes instead of IDs 并将标识放在它所属的位置:每个评论的容器。你可以试试:

  1. 为每个评论的容器添加一个 ID:

    <div class="panel panel-default">
    {% for comment in spot.ordered_comments %}
      <div class="panel-heading row" id="comment-{{ comment.id }}">
        ...
    
  2. 在模态模板中使用类而不是 ID:

    <!-- editmodal.html -->
    {% load static %}
    
    <div class="modal fade editModal" tabindex="-1" ...>
      ...
    
  3. 将按钮中的data-target 更改为:

    <li><a href="#" data-toggle="modal" data-target="#editModal">Edit</a></li>
    

    到:

    <li><a href="#" data-toggle="modal" data-target="#comment-{{ comment.id }} .editModal">Edit</a></li>
    

【讨论】:

    【解决方案2】:

    看起来您所有的编辑模式都将具有相同的 id id="editModal" 以及您的回复模式 id="replyModal" 如果您基于 id 显示它们,您可能总是会打开具有该 id 的第一个 DOM 元素。您可以尝试附加一个唯一标识符,例如 forloop.counter

    https://docs.djangoproject.com/en/1.9/ref/templates/builtins/#for

    【讨论】:

      猜你喜欢
      • 2010-12-28
      • 1970-01-01
      • 2014-08-24
      • 1970-01-01
      • 1970-01-01
      • 2019-12-19
      • 2018-09-08
      • 1970-01-01
      • 2012-07-13
      相关资源
      最近更新 更多