【问题标题】:How to iterate over attributes of an object using Jinja如何使用 Jinja 迭代对象的属性
【发布时间】:2021-07-28 18:08:24
【问题描述】:

我有一个咖啡豆模型,我将它发送到我的HTML 页面并显示对象的数据。目前,我有一个解决方案,如果我修改我的Bean 对象,我需要更新我的HTML 代码。

我想通过迭代与对象关联的属性而不是将每个属性硬编码到HTML 中来从我的程序中移除耦合。

我当前(过时的)解决方案:

# Bean model defined using Flask-SQLAlchemy
class Bean(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(20), index=True, nullable=False)
    ...
<!-- some_page.html -->
<table class="table">
        <thead>
            <tr>
                <th scope="col">#</th>
                <th scope="col">Name</th>
                ...
            </tr>
        </thead>
        <tbody>
            {% for bean in beans %}
            {% include '_bean_info.html' %}
            {% endfor %}
        </tbody>
</table>
<!-- _bean_info.html -->
<tr>
    <th scope="col">{{ bean.id }}</th>
    <th scope="col">{{ bean.name }}</th>
    ...
</tr>

我想做什么:

<!-- _bean_info.html -->
<tr>
    {% for each b in bean %}
        <th scope="col">
            {{ bean.b }} <!-- where 'b' is an attribute, e.g. 'name' -->
        </th>
</tr>

【问题讨论】:

  • 您的bean 模型是如何定义的?

标签: flask jinja2 flask-sqlalchemy


【解决方案1】:

根据您的数据结构的样子,您可以利用对象的属性可通过__dict__ 属性获得的事实......换句话说,如果我们有这样的数据:

from dataclasses import dataclass


@dataclass
class Bean:
    id: str
    name: str


beans = [
        Bean(id=1, name="Guatemalan"),
        Bean(id=2, name="Peruvian"),
        Bean(id=3, name="Hawaiian"),
        ]

然后我们可以在这样的模板中使用它:

import jinja2

t = jinja2.Template('''
<table>
{% for bean in beans %}
<tr>
{% for attr in bean.__dict__.keys() -%}
    <td>{{ attr }}</td><td>{{ bean[attr] }}</td>
{% endfor -%}
</tr>
{% endfor %}
</table>
''')

print(t.render(beans=beans))

综合起来,上面的例子会产生:

<table>

<tr>
<td>id</td><td>1</td>
<td>name</td><td>Guatemalan</td>
</tr>

<tr>
<td>id</td><td>2</td>
<td>name</td><td>Peruvian</td>
</tr>

<tr>
<td>id</td><td>3</td>
<td>name</td><td>Hawaiian</td>
</tr>

</table>

...这是我认为你想要的。


在这种特殊情况下,我可能会明确地将我的模型转换为dict,因为这会使模板不那么神奇:

from dataclasses import dataclass, asdict

...

t = jinja2.Template('''
<table>
{% for bean in beans %}
<tr>
{% for attr in bean.keys() -%}
    <td>{{ attr }}</td><td>{{ bean[attr] }}</td>
{% endfor -%}
</tr>
{% endfor %}
</table>
''')

print(t.render(beans=(asdict(bean) for bean in beans)))

【讨论】:

  • 这个解决方案有点工作。它在当前状态下不起作用,但我认为我可以使用这个概念。不过,我遇到的少数问题之一是它会打印对象的位置 - 是否有忽略某些属性?
  • @JakeJackson 你可以使用startswith in jinja。也许{% if not attr.startswith('_') %} 或声明一个变量,它是您确实想要的属性序列。
  • 谢谢,这确实有帮助。但是,我遇到的另一个问题是行与表的标题不匹配。我只打印attr 来测试它,它们完全不匹配,甚至不只是正确的顺序,而是转移了。
  • 如果您明确定义列名,那么只需按照@sytech 的建议将它们放入一个变量中,并使用它来生成列标题以及选择从对象中获取的属性。否则,从beans 列表中的第一项获取列名(例如beans.0.keys())。
猜你喜欢
  • 1970-01-01
  • 2022-11-21
  • 2022-07-14
  • 2023-03-24
  • 2015-11-07
  • 2014-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多