python - Cycle through 2D list with Jinja
问题描述
For simplicity, I will make a hypothetical which is equivalent to my current situation. I am using Flask as a backend to render Jinja templates for the frontend. Suppose I have a list of classes, each class being a list of students (Python classes/nodes with attributes and all). I want to render a single "class of students" at a time, and have buttons to cycle to the next group of students. Here is an example of how that looks:
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>
I would like these buttons to re-render this list as if the index incremented/decremented respectively. I do not want this to be done through URL parameters (e.g. page_url/number). How can I achieve this affect, and if possible, without a page refresh?
解决方案
这类似于分页。首先,您可以创建一个简单的分页对象以更好地帮助正确查找新索引的页面,同时还可以控制下一页和上一页的索引:
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)})
笔记:
self.data
inPagination
可以替换为数据库查询等,如果您的项目是这种情况StudentList
如果所有列表值都是基本数据类型,则用于更清晰地呈现模板。在您的示例中,没有必要,因为您提到您的列表已经存储了自定义类对象,并且yield i
可以替换为yield StudentList(i)
.
推荐阅读
- xml - 无效的 XML 字符错误 - 如何从 VARCHAR2 数据库列中查找无效字符?
- r - 使用 igraph 将节点属性分配给边权重
- vhdl - SDRAM 上的帧缓冲区
- ios - 如何将响应从 swift 传递给 Flutter?
- javascript - 尝试将更新推送到 vue 数据变量时,“blogItems”未定义
- xaml - Xamarin 数据绑定 - 通过 ItemList 显示来自自定义类的数据的问题
- python - ATM卡密码验证-Python
- if-statement - 当字符串的 Arraylist 为空时崩溃
- r - 我怎样才能另一个图例框并更改条形图的颜色?
- python - 带有 HTML 的 Python 电子邮件包