如何将Django原生SQL查询结果渲染为表头与字段名一致的HTML表格
解决方案
方案说明
你使用Post.objects.raw()执行原生SQL返回的是RawQuerySet实例,每个元素依然是Post模型的实例,和普通ORM查询得到的对象属性完全一致,仅需补充表头元数据到上下文即可实现通用渲染,无需硬编码HTML表格结构。
1 视图层调整(含安全修复)
首先修正原有代码的SQL注入风险,不要用f字符串拼接SQL参数,改用raw方法的params传参,同时补充要展示的字段和表头信息到上下文:
def posts_discussione(request,pk): discussione = Discussione.objects.get(pk=pk) # 定义你需要展示的字段列表,可按需增减 display_fields = ['autorePost', 'dataCreazione', 'contenuto'] # 自动获取模型字段的verbose_name作为表头,也可自定义列表如['作者','日期','内容'] headers = [Post._meta.get_field(field).verbose_name for field in display_fields] # 修复SQL注入风险,参数通过params传入 posts = Post.objects.raw('SELECT * from forum_post where discussione_id = %s order by dataCreazione ASC', [pk]) context = { 'posts':posts, 'discussione':discussione, 'headers': headers, 'display_fields': display_fields } return render(request,'posts-discussione.html',context)
2 模板层调整
修改HTML模板,动态生成表头和表格内容,无需硬编码字段:
<table> <thead> <tr> {% for header in headers %} <th>{{header}}</th> {% endfor %} </tr> </thead> <tbody> {% for post in posts %} <tr> {% for field in display_fields %} <td>{{ post|getattr:field }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table>
注:如果模板不支持getattr过滤器,可自行注册一个简单的模板过滤器,代码如下:
# 在你的app下的templatetags/custom_filters.py中添加 from django import template register = template.Library() @register.filter def getattr(obj, attr): return getattr(obj, attr, '')
在模板顶部引入即可使用:{% load custom_filters %}
无模型绑定原生查询适配方案
如果你后续使用完全不绑定模型的原生查询(比如直接用connection.cursor执行SQL),可以直接获取表头和查询结果字典传入上下文:
from django.db import connection def your_view(request): with connection.cursor() as cursor: cursor.execute('SELECT id,name,create_time from some_table where status = %s', [1]) # 获取表头 headers = [col[0] for col in cursor.description] # 获取结果字典列表 rows = [dict(zip(headers, row)) for row in cursor.fetchall()] return render(request, 'your_template.html', {'headers': headers, 'rows': rows})
模板使用方式和上述一致,仅需把post|getattr:field换成{{ row.field }}即可。
内容的提问来源于stack exchange,提问作者kris9951
相关产品推荐
相关产品推荐

