【问题标题】:Cycle through 2D list with Jinja使用 Jinja 循环浏览 2D 列表
【发布时间】:2018-12-08 18:35:04
【问题描述】:

为简单起见,我将做一个与我目前的情况相当的假设。我使用 Flask 作为后端来为前端呈现 Jinja 模板。假设我有一个类列表,每个类都是一个学生列表(具有属性的 Python 类/节点和所有)。我想一次渲染一个“学生班级”,并有按钮循环到下一组学生。这是一个外观示例:

app.py

@app.route('/', methods=['GET', 'POST'])
def get_students():
    groups = None
    # some calculations and algorithms
    groups = [['foo', 'bar'], ['baz', 'boo']]
    return render_template('index.html', groups=groups, index=0)

index.html

{% if groups %}
{% set display_group = groups[index] %}
    <ul id="students" class="">
        {% for student in display_group %}
            <li class="student">{{ student.name }}</li>
        {% endfor %}
    </ul>
{% endif %}
<button onclick="next_group()">Next Group</button>
<button onclick="prev_group()">Previous Group</button>

我希望这些按钮重新呈现此列表,就像索引分别递增/递减一样。我不希望通过 URL 参数(例如 page_url/number)来完成此操作。如何在不刷新页面的情况下实现这种效果,如果可能的话?

【问题讨论】:

    标签: python ajax flask jinja2


    【解决方案1】:

    这是 javascript 的工作,而不是 jinja 模板系统,当您将模板发送回客户端时,它会根据组成它的变量进行预格式化。您应该有一个通过 java 脚本中的 ajax 调用调用的端点,而不是返回 render_template 而是返回您的组的 json,并通过 JS 操作 DOM,jinja 将无法做到这一点,尽管您可以发送 javascript通过 Jinja 模板系统形成。

    【讨论】:

      【解决方案2】:

      这类似于分页。首先,您可以创建一个简单的分页对象,以更好地帮助正确查找新索引的页面,同时还可以控制下一页和上一页的索引:

      import typing
      
      class StudentList(typing.NamedTuple):
        name:str
      
      class Pagination:
        def __init__(self, _num = 1):
           self.num = _num
           self.data = [['foo', 'bar'], ['baz', 'boo'], ['first', 'last']]
        @property
        def has_next(self):
           return self.num < len(self.data)
        @property
        def has_previous(self):
           return self.num > 0
        @property
        def next(self):
           return self.num + 1
        @property
        def previous(self):
           return self.num - 1
        def __iter__(self):
           for i in self.data[self.num-1]:
              yield StudentList(i)
      

      接下来,为了创建动态查找,需要两个html:主页,用javascript控制按钮点击并与后端通信,html作为查询的一部分返回通过ajax 发送到后端。首先,创建查询html

      students_and_classes.html:

      <div class='student_class'>
       {%for student in lecture%} 
         <span class='student'>Name: {{student.name}}</span>
       {%endfor%}
       {%if lecture.has_previous%}
         <button id='previous_{{lecture.previous}}'>Previous</button>
       {%endif%}
       {%if lecture.has_next%}
         <button id='next_{{lecture.next}}'>Next</button>
       {%endif%}
       <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
       <script>
       $(document).ready(function() {
        $('button').click(function(event) {
         var result = event.target.id;
         $.ajax({
          url: "/update_page",
          type: "get",
          data: {results: result},
          success: function(response) {
          $("#pagination_results").html(response.html);
          },
          error: function(xhr) {
           $("#pagination_results").html('<p>Opps, something when wrong</p>');
          }
         });
        });
       });
      </script>
      </div>
      

      第二,显示完整学生分页的页面,以及jqueryajax

      main.html:

      <html>
        <body>
          <div id='pagination_results'>
            <div class='student_class'>
            {%for student in lecture%} 
              <span class='student'>Name: {{student.name}}</span>
            {%endfor%}
            {%if lecture.has_previous%}
              <button id='previous_{{lecture.previous}}'>Previous</button>
            {%endif%}
            {%if lecture.has_next%}
              <button id='next_{{lecture.next}}'>Next</button>
           {%endif%}
          </div>
          </div>
        </body>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
        <script>
        $(document).ready(function() {
         $('button').click(function(event) {
          var result = event.target.id;
          $.ajax({
            url: "/update_page",
            type: "get",
            data: {results: result},
            success: function(response) {
            $("#pagination_results").html(response.html);
           },
           error: function(xhr) {
            $("#pagination_results").html('<p>Opps, something when wrong</p>');
          }
         });
       });
      });
      </script>
      </html>
      

      最后,在所需的路由中(在本例中为“/”),可以创建服务main.html 的路由:

      @app.route('/', methods = ['GET'])
      def home():
        return flask.render_template('main.html', lecture=Pagination())
      

      然后,需要创建从ajaxGET方法接收数据的路由:

      import re
      @app.route('/update_page')
      def update_page():
        _r = flask.request.args.get('results')
        _l = Pagination(int(re.findall('\d+$', _r)[0]))
        return flask.jsonify({'html':flask.render_template('students_and_classes.html', lecture=_l)})
      

      注意事项:

      1. Pagination 中的 self.data 可以替换为数据库查询等,如果您的项目是这样的话
      2. 如果所有列表值都是基本数据类型,StudentList 用于更清晰地呈现模板。在您的示例中,没有必要,因为您提到您的列表已经存储了自定义类对象,yield i 可以替换为yield StudentList(i)

      【讨论】:

      • 感谢您的回答。我得到了这个与我的设置一起工作。我最终序列化了我的对象,以便我可以通过 cookie(而不是数据库查询)检索数据。我遇到的问题有点奇怪。按钮只能在任一方向工作一次,然后再无法操作。甚至没有调用脚本事件侦听器,我不知道为什么。
      • @adapap 抱歉,我忘记在students_and_classes.html 中包含&lt;script&gt;&lt;/script&gt; 之间的javascript,而不仅仅是main.html。当我测试它时,它目前对我有用。请查看我最近的编辑。
      猜你喜欢
      • 2023-03-22
      • 2020-10-14
      • 2016-08-08
      • 1970-01-01
      • 1970-01-01
      • 2020-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多