[Answered ]-Django prefetch_related with 3 not directly related Models

1👍

You .select_related the wrong relation, you should fetch VID, so:

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})

then in the template you can work with:

<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>

Your clientvul model however acts as a junction table for a many-to-many relation between client and vul. You can span a ManyToManyField [Django-doc] on the client model with:

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

Then you can simplify this to:

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

and in the template, use:

<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>

Note: Models in Django are written in PascalCase, not snake_case,
so you might want to rename the model from ClientVul to clientvul.


Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: cvs_score instead of CVSScore.

Leave a comment