Django prefetch_related与3个不直接相关的模型

a64a0gku  于 2023-05-19  发布在  Go
关注(0)|答案(1)|浏览(160)

我的Django APP里有三个模特。

模型.py

from django.db import models
from django.contrib import admin

class client(models.Model):
    hostname= models.CharField(max_length=50,primary_key=True)
    user= models.CharField(max_length=100)
    
class vul(models.Model):
    VID=models.IntegerField(primary_key=True)
    CVELIST=models.CharField(max_length=50)
    CVSScore=models.FloatField(max_length=5)
    Serverity=models.CharField(max_length=25)
    Title=models.CharField(max_length=1000)
    Summary=models.CharField(max_length=1000)

class clientvul(models.Model):
    
    hostname= models.ForeignKey(client, on_delete=models.CASCADE)
    VID=models.ForeignKey(vul, on_delete=models.CASCADE)
    Path=models.CharField(max_length=1000)
    isActive=models.BooleanField(default=True)
    class Meta:
        constraints = [
            models.UniqueConstraint(
               fields=['hostname', 'VID'], name='unique_migration_host_combination'
            )
        ]


admin.site.register(ClientDB)
admin.site.register(VULDB)
admin.site.register(ClientVULDB)

我的视图:

def index(request):
    qs = client.objects.prefetch_related(
          Prefetch('clientvuldb_set', clientvul.objects.select_related('hostname')))
 
    print(qs)
    return render(request, 'browseDB.html', {'data':qs})

我的模板

<tbody>
          {% for row in data %}
          <tr>
            <td class="hostname">{{ row.hostname}}</td>
            <td class="User">{{ row.user }}</td>
            <td class="Vulnerabilites">
              <select class="form-select" size="4">
                {% for subitem in data%}
                <option>{{ subitem.Title }}</option>
                {% endfor %}
              </select>
            </td>
            <td>
              <button class="btn btn-outline-success sign" type="button" data-bs-toggle="modal" data-bs-target="#myModal">Show-Info</button>
            </td>
          </tr>
          {% endfor %}
        </tbody>

我想在我的模板上显示按主机名分组的数据:
主机名(客户端)、用户(客户端)、标题(vul)
所以我不知道在哪里我可以“组”的数据,但任何帮助将appriciated:)
在StackOverflow上已经问过:Django prefetch_related over 3 models (one "relationship Model"
但我想我没有很好地阐述这个问题。

mpgws1up

mpgws1up1#

.select_related错误的关系,你应该获取VID,所以:

from django.db.models import Prefetch

def index(request):
    qs = client.objects.prefetch_related(
        Prefetch('clientvul_set', clientvul.objects.select_related('VID'))
    )
    return render(request, 'browseDB.html', {'data': qs})

然后在模板中,您可以使用:

<tbody>
  {% for row in data %}
  <tr>
    <td class="hostname">{{ row.hostname}}</td>
    <td class="User">{{ row.user }}</td>
    <td class="Vulnerabilites">
      <select class="form-select" size="4">
        {% for subitem in row.clientvul_set.all %}
            <option>{{ subitem.VID.Title }}</option>
        {% endfor %}
      </select>
    </td>
    <td>
      <button class="btn btn-outline-success sign" type="button" data-bs-toggle="modal" data-bs-target="#myModal">Show-Info</button>
    </td>
  </tr>
  {% endfor %}
</tbody>

但是,您的clientvul模型充当clientvul之间多对多关系的连接表。您可以在client模型上使用以下命令生成**ManyToManyField**[Django-doc]:

class client(models.Model):
    # …
    vuls = models.ManyToManyField(
        'vul',
        through='clientvul',
        related_name='clients'
    )

然后你可以将其简化为:

def index(request):
    qs = client.objects.prefetch_related('vuls')
    return render(request, 'browseDB.html', {'data': qs})

在模板中,用途:

<tbody>
  {% for row in data %}
  <tr>
    <td class="hostname">{{ row.hostname}}</td>
    <td class="User">{{ row.user }}</td>
    <td class="Vulnerabilites">
      <select class="form-select" size="4">
        {% for subitem in row.vuls.all %}
            <option>{{ subitem.Title }}</option>
        {% endfor %}
      </select>
    </td>
    <td>
      <button class="btn btn-outline-success sign" type="button" data-bs-toggle="modal" data-bs-target="#myModal">Show-Info</button>
    </td>
  </tr>
  {% endfor %}
</tbody>

注意:Django中的模型是用 PascalCase 编写的,而不是 snake_case,所以你可能想把模型从ClientVul重命名为clientvul
注意:通常Django模型中字段的名称都是用 snake_case 而不是 PascalCase 写的,所以应该是:cvs_score而不是CVSScore

相关问题