如何在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过滤器可动态获取对象属性,同时过滤掉非数据库字段:
- 修改表格内容遍历部分:
<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)动态获取实例对应值。
- 表头部分也建议加上过滤,避免显示冗余列:
<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
相关产品推荐
相关产品推荐

