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 полями, они устанавливаются в возвращаемых экземплярах модели необработанным набором запросов.

Вернуться на верх