Django在for循环中包含模板标签只捕获第一次迭代

ele*_*han 5 python django closures loops django-templates

我在我的网站上的一些页面上有一个评论部分,我用一个{% for ... %}循环构建(还有另一个用于评论回复的嵌套循环。该部分被黑客攻击在一起,我仍在学习 Web 开发和 Django,所以请原谅任何令人沮丧的草率或怪异. 我现在不关心效率,只关心效率,现在还不太合适。

对于每条评论,我都有一个 Bootstrap 下拉按钮,可以显示选项EditDelete. Edit将打开一个模式来编辑评论。模态是用{% 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>
Run Code Online (Sandbox Code Playgroud)

这是编辑模式:

<!-- 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>
Run Code Online (Sandbox Code Playgroud)

和回复模式:

<!-- 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>
Run Code Online (Sandbox Code Playgroud)

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

我用以下视图进行了测试:

def test(request):
    spots = Spot.objects.all()
    return render(request, 'test.html', {'spots': spots})
Run Code Online (Sandbox Code Playgroud)

和模板:

<!-- test.html -->
<h1>Hello world</h1>
{% for spot in spots %}
    {% include 'testinclude.html' %}
{% endfor %}
Run Code Online (Sandbox Code Playgroud)

<!-- testinclude.html -->
<h3>{{ spot.name }}</h3>
Run Code Online (Sandbox Code Playgroud)

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

Yat*_*wal 6

正如emulbreh 假设的那样,实际上每个评论都会呈现一个模式。但是,所有模态框都具有相同的 ID,因此无论单击哪个 comment\xe2\x80\x99s 编辑按钮,每次都会触发第一个模态框。ID 在 HTML 文档中应该是唯一的。

\n\n

你该如何解决这个问题?您可以使每个评论的模态 ID 都是唯一的。id="editModal-{{ comment.id }}"您可以通过写入或仅获取唯一标识符id="editModal-{{ forloop.counter }}此处的文档)。

\n\n

但是您的editModal.html模板与 \xe2\x80\x98master\xe2\x80\x99 模板紧密耦合。更好的解决方案是使用类而不是 ID,并将标识放在它所属的位置:每个评论的容器。你可以试试:

\n\n
    \n
  1. 向每个 comment\xe2\x80\x99s 容器添加 ID:

    \n\n
    <div class="panel panel-default">\n{% for comment in spot.ordered_comments %}\n  <div class="panel-heading row" id="comment-{{ comment.id }}">\n    ...\n
    Run Code Online (Sandbox Code Playgroud)
  2. \n
  3. 在模态模板中使用类而不是 ID,如下所示:

    \n\n
    <!-- editmodal.html -->\n{% load static %}\n\n<div class="modal fade editModal" tabindex="-1" ...>\n  ...\n
    Run Code Online (Sandbox Code Playgroud)
  4. \n
  5. data-target将按钮更改为:

    \n\n
    <li><a href="#" data-toggle="modal" data-target="#editModal">Edit</a></li>\n
    Run Code Online (Sandbox Code Playgroud)\n\n

    到:

    \n\n
    <li><a href="#" data-toggle="modal" data-target="#comment-{{ comment.id }} .editModal">Edit</a></li>\n
    Run Code Online (Sandbox Code Playgroud)
  6. \n
\n