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
Ответы (1 шт):
Для получения связанных записей по FK одним запросом используйте select_related
subdivisions = Subdivision.objects.prefetch_related(
Prefetch('children_subdivision', Persone.objects.all().select_related('employee_position'))
)
UPD: Извиняюсь, не заметил пару моментов. В общем, нельзя для Subdivision сделать select_related, делайте для Persone, который в prefetch
