Циклический просмотр списка 2D с Jinja - PullRequest
0 голосов
/ 29 июня 2018

Для простоты я сделаю гипотезу, которая эквивалентна моей нынешней ситуации. Я использую 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). Как я могу добиться этого эффекта и, если возможно, без обновления страницы?

Ответы [ 2 ]

0 голосов
/ 29 июня 2018

Это похоже на нумерацию страниц. Во-первых, вы можете создать простой объект разбиения на страницы, чтобы лучше помочь с правильным поиском страницы для нового индекса, а также контролировать индексы для следующей страницы и предыдущей страницы:

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>

Во-вторых, страница для отображения полной нумерации студентов вместе с jquery и ajax:

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())

Затем необходимо создать маршрут для получения данных из метода ajax GET:

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. self.data в Pagination можно заменить запросом к базе данных и т. Д., Если это имеет место в вашем проекте
  2. StudentList используется для более чистой визуализации шаблона, если все значения списка являются основными типами данных. В вашем примере это не нужно, поскольку вы упоминаете, что в ваших списках уже хранятся объекты пользовательских классов, и yield i можно заменить на yield StudentList(i).
0 голосов
/ 29 июня 2018

Это работа для javascript, а не для системы шаблонов jinja, когда вы отправляете шаблон обратно клиенту, предварительно отформатированный в соответствии с составляющими его переменными. У вас должна быть конечная точка, которая будет вызываться с помощью вызовов ajax в java-скрипте, чтобы не возвращать render_template, а чтобы возвращать json ваших групп и манипулировать DOM через JS, jinja не сможет этого сделать, хотя вы можете отправить javascript формируется через систему шаблонов Jinja.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...