Django中如何在单个HTML表格展示站点过滤的多设备模型数据?
解决Django多模型数据在单个表格渲染的问题
问题根源
- 请求方式不匹配:模板1通过
<a>标签跳转属于GET请求,但你的ReportView仅实现了post方法,无法处理该请求。 - 上下文变量覆盖:多次给
context["site"]赋值会导致后续值覆盖前序值,最终仅保留打印机数据。 - 查询方法错误:
get()仅能返回单个对象,若站点下存在多个同类型设备会抛出异常,应使用filter()获取查询集。 - 参数处理逻辑缺失:URL传入的是站点名称,需先找到对应的
Site对象,再用该对象过滤关联设备。
修正后的代码
1. 视图层(ReportView)
from django.views.generic import TemplateView from .models import Site, Workstation, Laptop, Printer class ReportView(TemplateView): template_name = "mytestapp/report.html" def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 从URL参数获取站点名称,匹配对应Site对象 site_name = kwargs.get('sitename') target_site = Site.objects.get(site_name=site_name) # 获取该站点下所有设备并合并为列表 workstations = Workstation.objects.filter(sitename=target_site) laptops = Laptop.objects.filter(sitename=target_site) printers = Printer.objects.filter(sitename=target_site) context['devices'] = list(workstations) + list(laptops) + list(printers) context['current_site'] = target_site # 传递站点信息用于页面展示 return context
2. 模板层(report.html)
首先在模板顶部加载自定义过滤器:
{% load device_tags %}
然后编写表格代码:
<h2>{{ current_site.site_name }} 设备清单</h2> <table> <tr> <th>设备类型</th> <th>设备名称</th> <th>序列号</th> <th>型号</th> </tr> {% for device in devices %} <tr> <!-- 判断设备类型并显示 --> <td> {% if device|instanceof:"Workstation" %}工作站 {% elif device|instanceof:"Laptop" %}笔记本电脑 {% elif device|instanceof:"Printer" %}打印机 {% endif %} </td> <td>{{ device.name }}</td> <td>{{ device.serial }}</td> <td> <!-- 显示对应型号字段 --> {% if device|instanceof:"Workstation" %}{{ device.workstation_model }} {% elif device|instanceof:"Laptop" %}{{ device.laptop_model }} {% elif device|instanceof:"Printer" %}{{ device.printer_model }} {% endif %} </td> </tr> {% empty %} <tr> <td colspan="4">该站点暂无设备记录</td> </tr> {% endfor %} </table>
3. 自定义模板过滤器(instanceof)
在app目录下创建templatetags文件夹,添加以下两个文件:
templatetags/__init__.py(空文件即可)templatetags/device_tags.py:
from django import template from mytestapp.models import Workstation, Laptop, Printer register = template.Library() @register.filter def instanceof(value, model_name): model_map = { 'Workstation': Workstation, 'Laptop': Laptop, 'Printer': Printer } return isinstance(value, model_map.get(model_name))
可选优化:模型抽象基类
三个设备模型字段高度重复,可通过抽象基类减少代码冗余:
from django.db import models class Device(models.Model): name = models.CharField(max_length=30, blank=True, null=True) serial = models.CharField(max_length=30, blank=True, null=True) sitename = models.ForeignKey(Site, on_delete=models.SET_NULL, blank=True, null=True, verbose_name="Site") class Meta: abstract = True class Workstation(Device): workstation_model = models.CharField(max_length=30, blank=True, null=True, verbose_name="Workstation Model") def __str__(self): return self.name class Laptop(Device): laptop_model = models.CharField(max_length=30, blank=True, null=True, verbose_name="Laptop Model") def __str__(self): return self.name class Printer(Device): printer_model = models.CharField(max_length=30, blank=True, null=True, verbose_name="Printer Model") def __str__(self): return self.name
内容的提问来源于stack exchange,提问作者Jstnice
相关产品推荐
相关产品推荐

