You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django中动态将数据库查询结果渲染为HTML表格?

问题

我想把数据库的简单查询结果显示成HTML表格,但Django模板或数据逻辑里有疏漏。

先创建了模型:

class Book(models.Model):
    title = models.CharField(max_length=128, unique=True)
    quantity = models.IntegerField(default=1)

然后写了视图,把查询对象和列名传入上下文:

def books(request):
    context = {"rows": Book.objects.all(), "fields": Book._meta.get_fields()}
    return render(request, "blog/books.html", context)

最后在模板里遍历生成表格:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Our Books</title>
</head>
<body>

    <table border="1">
        <thead>
            <tr>
                {% for field in fields %}
                    <th>{{ field.verbose_name }}</th>
                {% endfor %}
            </tr>
        </thead>
        <tbody>
            {% for row in rows %}
                <tr>
                    {% for field in fields %}
                        <td>{{ row[field] }}</td>
                    {% endfor %}
                </tr>
            {% endfor %}
        </tbody>
    </table>

</body>
</html>

表格表头能正常显示,但表格内容部分无法工作,也就是这段代码:

{% for row in rows %}
    <tr>
         {% for field in fields %}
             <td>{{ row[field] }}</td>
         {% endfor %}
    </tr>
{% endfor %}

我试过这些方法都没用:

  • row[field]
  • row[field.verbose_name]
  • row.field
  • {{ row.__dict__.get(field.verbose_name) }}
  • 其他更多方法

我不想在模板里硬编码列名,想要一个能适配任意表格的通用遍历方案,该怎么解决?

解决方案

核心问题有两个:一是Django模板不支持row[field]这种字典式访问模型实例属性,二是Book._meta.get_fields()会返回反向关联字段(比如外键的反向引用),这类字段无法直接获取有效值。

方法一:模板内用getattr过滤器(推荐)

Django内置getattr过滤器可动态获取对象属性,同时过滤掉非数据库字段:

  1. 修改表格内容遍历部分:
<tbody>
    {% for row in rows %}
        <tr>
            {% for field in fields %}
                {% if field.concrete %}
                    <td>{{ row|getattr:field.name }}</td>
                {% endif %}
            {% endfor %}
        </tr>
    {% endfor %}
</tbody>
  • field.concrete用于判断是否为数据库实际存在的字段,排除反向关联等虚拟字段;
  • row|getattr:field.name通过字段的name属性(模型中定义的字段名,如title、quantity)动态获取实例对应值。
  1. 表头部分也建议加上过滤,避免显示冗余列:
<thead>
    <tr>
        {% for field in fields %}
            {% if field.concrete %}
                <th>{{ field.verbose_name }}</th>
            {% endif %}
        {% endfor %}
    </tr>
</thead>

方法二:视图中预处理数据

如果不想在模板中添加过多逻辑,可在视图中将每条数据转为字典后传入模板:

def books(request):
    # 筛选出所有数据库实际字段
    fields = [field for field in Book._meta.get_fields() if field.concrete]
    # 将每个Book实例转为字典,键为字段名
    rows = []
    for book in Book.objects.all():
        row_dict = {field.name: getattr(book, field.name) for field in fields}
        rows.append(row_dict)
    context = {"rows": rows, "fields": fields}
    return render(request, "blog/books.html", context)

之后模板中可直接通过字段名访问:

<td>{{ row[field.name] }}</td>

额外提示

  • 若需要排除特定字段(比如主键id),可在过滤字段时添加判断:if field.concrete and field.name != 'id';
  • 对于ForeignKey等关联字段,直接获取会返回关联对象,可在关联模型中定义__str__方法控制显示内容,或在模板中进一步处理(如{{ row|getattr:field.name|str }})。

内容的提问来源于stack exchange,提问作者Adikte

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 22:46:26