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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 12:52:25