Django оптимизация запросов к БД

Три модели: Subdivision (mptt), Position (самая обычная), Persone (имеет два ForeignKey, на Subdivision и Position). Не могу оптимизировать запросы к БД для вывода данных в темплейте. В темплейте хочу рекурсивно выводить всю структуру подразделений (через mptt) и в каждом подразделении указывать всех работающих в нём сотрудников и их данные (из Persone и Position).

Составил модель:

class Subdivision(MPTTModel):
    subdivision_name = models.CharField(max_length=200)
    parent = TreeForeignKey('self', on_delete=models.CASCADE,
                            null=True, blank=True, related_name='children_sub')

    class MPTTMeta:
        order_insertion_by = ['subdivision_name']


class Position(models.Model):
    employment_position = models.CharField(max_length=200, null=True, blank=True)
    salary = models.IntegerField()


class Persone(models.Model):
    name = models.CharField(max_length=50, null=True, blank=True)
    employee_position = models.ForeignKey(Position, on_delete=models.SET_NULL, null=True,
                               blank=True, related_name='children_position')
    employee_subdivision = TreeForeignKey(Subdivision, on_delete=models.SET_NULL, null=True,
                               blank=True, related_name='children_subdivision')

view.py:

def show_subdivisions(request):
    global subdivisions
    subdivisions = Subdivision.objects.prefetch_related('children_subdivision')
    context = {'subdivisions': subdivisions}
    return render(request, "subdivisions.html", context)

Мой темплейт:

{% load mptt_tags %}
{% recursetree subdivisions %}
    {% if node.is_leaf_node %}
            Подразделение {{ node.subdivision_name }}<br>
            {% if node.children_subdivision.all %}
                Тут работают:<br>
                {% for employee in node.children_subdivision.all %}
                       {{ employee.name }};
                       Должность = {{ employee.employee_position.employment_position }};
                       Зар. плата = {{ employee.employee_position.salary }}<br>
                {% endfor %}
            {% endif %}
    {% else %}
            Подразделение {{ node.subdivision_name }}<br>
            {% if node.children_subdivision.all %}
                Тут работают:<br>
                {% for employee in node.children_subdivision.all %}
                       {{ employee.name }};
                       Должность = {{ employee.employee_position.employment_position }};
                       Зар. плата = {{ employee.employee_position.salary }}<br>
                {% endfor %}
            {% endif %}
        <ul class="nested">
            {{ children }}
        </ul>
    {% endif %}     
{% endrecursetree %}
ps - я убрал строчки таблиц и стилей, чтоб меньше места занимал код.

Идея 1: изначально во вьюхе было subdivisions = Subdivision.objects.all() и в моем тестовом примере получалось 18 запросов в БД, после добавления prefetch_related стало 9.

Как я понимаю, благодаря prefetch_related во вьюхе вытаскиваются все подразделения вместе с инфой о Персонах в каждом подразделении. Но ! Мы так же хотим знать employee_position каждой персоны. И когда я это делаю в темплейте, то создается куча однотипных запросов (см картинку), которые по идее можно оптимизировать. Но я не могу придумать как это сделать.

Буду благодарен за подсказку.

ps весь код тут github.com/University169/traffic_light/tree/alternate_v1

когда сделал prefetch_related


Ответы (1 шт):

Автор решения: Za Ars

Для получения связанных записей по FK одним запросом используйте select_related

subdivisions = Subdivision.objects.prefetch_related(
    Prefetch('children_subdivision', Persone.objects.all().select_related('employee_position'))
)

UPD: Извиняюсь, не заметил пару моментов. В общем, нельзя для Subdivision сделать select_related, делайте для Persone, который в prefetch

→ Ссылка