Django неожиданное количество выполненных запросов
дано models.py
:
from django.db import models
class Menu(models.Model):
name = models.CharField(max_length=255)
menu_url = models.CharField(max_length=255)
def __str__(self):
return self.name
class MenuEntry(models.Model):
menu = models.ForeignKey("menu", null=True, blank=True,
on_delete=models.CASCADE)
parent = models.ForeignKey("menuentry", null=True,
blank=True,
on_delete=models.CASCADE)
text = models.CharField(max_length=255)
def __str__(self):
return self.text
при выполнении в другом файле draw_menu.py
происходит следующее:
from django import template
from menu.models import MenuEntry
from django.db import connection
register = template.Library()
@register.simple_tag
def draw_menu_tag(menu_name):
queryset = MenuEntry.objects.raw("WITH RECURSIVE \
my_menu_items \
AS( \
SELECT * FROM menu_menuentry WHERE menu_menuentry.menu_id=(SELECT id FROM \
menu_menu WHERE name=%s) \
UNION \
SELECT m.* FROM menu_menuentry m \
INNER JOIN my_menu_items r ON m.parent_id = r.id \
WHERE m.parent_id IS NOT NULL \
) \
SELECT * FROM my_menu_items mmi INNER JOIN menu_menu mm ON mm.id = mmi.menu_id", ["menu_B"])
q = list(queryset)
resulting_html = str(queryset_to_dict(q))
breakpoint()
return 'resulting_html'
def queryset_to_dict(queryset):
out_dict = {}
out_dict['menu'] = queryset[0].menu.name
out_dict['menu_url'] = queryset[0].menu.menu_url
num_queries = len(connection.queries)
print(f"Number of queries executed: {num_queries}")
return out_dict
при загрузке страницы с этим тегом я получаю сообщение "Количество выполненных запросов: 2". Ниже приводится дополнительный запрос
out_dict['menu'] = queryset[0].menu.name
Но я присоединил соответствующие пункты меню. Это должно быть получено без дополнительных запросов. Пожалуйста, помогите, большое спасибо!
Вы используете сырой набор запросов, и, похоже, Django не распознает, что вы объединили поля в сыром SQL. В документации об этом ничего не говорится: https://docs.djangoproject.com/en/5.0/topics/db/sql/#performing-raw-queries
Попробуйте следующий код:
from django import template
from menu.models import MenuEntry
from django.db import connection
register = template.Library()
@register.simple_tag
def draw_menu_tag(menu_name):
queryset = MenuEntry.objects.raw("WITH RECURSIVE \
my_menu_items \
AS( \
SELECT * FROM menu_menuentry WHERE menu_menuentry.menu_id=(SELECT id FROM \
menu_menu WHERE name=%s) \
UNION \
SELECT m.* FROM menu_menuentry m \
INNER JOIN my_menu_items r ON m.parent_id = r.id \
WHERE m.parent_id IS NOT NULL \
) \
SELECT * FROM my_menu_items mmi INNER JOIN menu_menu mm ON mm.id = mmi.menu_id", ["menu_B"])
q = list(queryset)
resulting_html = str(queryset_to_dict(q))
breakpoint()
return 'resulting_html'
def queryset_to_dict(queryset):
out_dict = {}
out_dict['menu'] = queryset[0].name
out_dict['menu_url'] = queryset[0].menu_url
num_queries = len(connection.queries)
print(f"Number of queries executed: {num_queries}")
return out_dict
Обратите внимание на прямой доступ к name
и menu_url
. Хотя они не являются фактическими MenuItem
полями, они устанавливаются в возвращаемых экземплярах модели необработанным набором запросов.