Django多关联模型按主机名分组展示数据问题求助
解决方案
1. 视图层:预取关联数据并完成分组
首先在视图中先获取关联漏洞的客户端数据,通过预取关联避免重复查询数据库,再用Python的itertools.groupby按hostname分组(注意必须先按hostname排序,groupby仅对连续相同的键分组)。
假设你的模型结构如下(如果和实际有差异,可对应调整字段名):
class Client(models.Model): hostname = models.CharField(max_length=100) user = models.CharField(max_length=50) class Vul(models.Model): title = models.CharField(max_length=200) class ClientVul(models.Model): client = models.ForeignKey(Client, on_delete=models.CASCADE) vul = models.ForeignKey(Vul, on_delete=models.CASCADE)
视图代码示例:
from django.shortcuts import render from itertools import groupby from .models import Client def client_vul_list(request): # 预取关联的漏洞数据,减少数据库查询次数 clients = Client.objects.filter( clientvul__isnull=False ).prefetch_related('clientvul_set__vul').order_by('hostname') # 按hostname分组,整理成模板需要的结构 grouped_data = [] for hostname, client_group in groupby(clients, key=lambda c: c.hostname): client_list = list(client_group) # 取同一hostname下的用户(如果同一hostname对应多用户,需调整分组键为(hostname, user)) user = client_list[0].user # 收集该主机下所有漏洞标题并去重 vul_titles = set() for client in client_list: for cv in client.clientvul_set.all(): vul_titles.add(cv.vul.title) grouped_data.append({ 'hostname': hostname, 'user': user, 'vul_titles': list(vul_titles) }) return render(request, 'vul_template.html', {'grouped_data': grouped_data})
2. 模板层:渲染分组后的数据
在模板中直接循环分组后的列表,结构清晰易读:
{% for group in grouped_data %} <div class="client-block"> <h3>主机名:{{ group.hostname }}</h3> <p>负责人:{{ group.user }}</p> <h4>关联漏洞:</h4> <ul> {% for title in group.vul_titles %} <li>{{ title }}</li> {% empty %} <li>无关联漏洞</li> {% endfor %} </ul> </div> {% empty %} <p>暂无主机漏洞数据</p> {% endfor %}
简化写法(如果中间表无额外字段)
如果ClientVul仅用于关联,没有额外字段,可以直接在Client模型中定义多对多关系,用through指定中间表,查询会更简洁:
class Client(models.Model): hostname = models.CharField(max_length=100) user = models.CharField(max_length=50) vuls = models.ManyToManyField(Vul, through='ClientVul')
视图可简化为:
clients = Client.objects.prefetch_related('vuls').order_by('hostname') grouped_data = [] for hostname, client_group in groupby(clients, key=lambda c: c.hostname): client = next(client_group) grouped_data.append({ 'hostname': hostname, 'user': client.user, 'vul_titles': [v.title for v in client.vuls.all()] })
内容的提问来源于stack exchange,提问作者jonat-han
相关产品推荐
相关产品推荐

